summaryrefslogtreecommitdiff
path: root/ports
diff options
context:
space:
mode:
Diffstat (limited to 'ports')
-rw-r--r--ports/alif/tinyusb_port/alif_dcd_reg.h16
-rw-r--r--ports/esp32/boards/ARDUINO_NANO_ESP32/mpconfigboard.cmake1
-rw-r--r--ports/esp32/boards/ARDUINO_NANO_ESP32/mpconfigboard.h5
-rw-r--r--ports/esp32/boards/ARDUINO_NANO_ESP32/sdkconfig.board7
-rw-r--r--ports/esp32/boards/ESP32_GENERIC_C5/board.json22
-rw-r--r--ports/esp32/boards/ESP32_GENERIC_C5/board.md2
-rw-r--r--ports/esp32/boards/ESP32_GENERIC_C5/mpconfigboard.cmake10
-rw-r--r--ports/esp32/boards/ESP32_GENERIC_C5/mpconfigboard.h7
-rw-r--r--ports/esp32/boards/ESP32_GENERIC_C5/sdkconfig.board2
-rw-r--r--ports/esp32/boards/ESP32_GENERIC_S2/mpconfigboard.cmake1
-rw-r--r--ports/esp32/boards/ESP32_GENERIC_S3/mpconfigboard.cmake1
-rw-r--r--ports/esp32/boards/LOLIN_S2_MINI/mpconfigboard.cmake1
-rw-r--r--ports/esp32/boards/LOLIN_S2_PICO/mpconfigboard.cmake1
-rw-r--r--ports/esp32/boards/M5STACK_ATOMS3_LITE/mpconfigboard.cmake1
-rw-r--r--ports/esp32/boards/UM_FEATHERS2/mpconfigboard.cmake1
-rw-r--r--ports/esp32/boards/UM_FEATHERS2NEO/mpconfigboard.cmake1
-rw-r--r--ports/esp32/boards/UM_FEATHERS3/mpconfigboard.cmake1
-rw-r--r--ports/esp32/boards/UM_FEATHERS3/mpconfigboard.h5
-rw-r--r--ports/esp32/boards/UM_FEATHERS3/sdkconfig.board9
-rw-r--r--ports/esp32/boards/UM_FEATHERS3NEO/mpconfigboard.cmake1
-rw-r--r--ports/esp32/boards/UM_FEATHERS3NEO/mpconfigboard.h5
-rw-r--r--ports/esp32/boards/UM_FEATHERS3NEO/sdkconfig.board9
-rw-r--r--ports/esp32/boards/UM_NANOS3/mpconfigboard.cmake1
-rw-r--r--ports/esp32/boards/UM_NANOS3/mpconfigboard.h5
-rw-r--r--ports/esp32/boards/UM_NANOS3/sdkconfig.board9
-rw-r--r--ports/esp32/boards/UM_OMGS3/mpconfigboard.cmake1
-rw-r--r--ports/esp32/boards/UM_OMGS3/mpconfigboard.h5
-rw-r--r--ports/esp32/boards/UM_OMGS3/sdkconfig.board9
-rw-r--r--ports/esp32/boards/UM_PROS3/mpconfigboard.cmake1
-rw-r--r--ports/esp32/boards/UM_PROS3/mpconfigboard.h5
-rw-r--r--ports/esp32/boards/UM_PROS3/sdkconfig.board9
-rw-r--r--ports/esp32/boards/UM_RGBTOUCH_MINI/mpconfigboard.cmake1
-rw-r--r--ports/esp32/boards/UM_RGBTOUCH_MINI/mpconfigboard.h5
-rw-r--r--ports/esp32/boards/UM_RGBTOUCH_MINI/sdkconfig.board9
-rw-r--r--ports/esp32/boards/UM_TINYS2/mpconfigboard.cmake1
-rw-r--r--ports/esp32/boards/UM_TINYS3/mpconfigboard.cmake1
-rw-r--r--ports/esp32/boards/UM_TINYS3/mpconfigboard.h5
-rw-r--r--ports/esp32/boards/UM_TINYS3/sdkconfig.board9
-rw-r--r--ports/esp32/boards/UM_TINYWATCHS3/mpconfigboard.cmake1
-rw-r--r--ports/esp32/boards/UM_TINYWATCHS3/mpconfigboard.h5
-rw-r--r--ports/esp32/boards/UM_TINYWATCHS3/sdkconfig.board9
-rw-r--r--ports/esp32/boards/sdkconfig.base1
-rw-r--r--ports/esp32/boards/sdkconfig.usb4
-rw-r--r--ports/esp32/esp32_common.cmake16
-rw-r--r--ports/esp32/esp32_rmt.c368
-rw-r--r--ports/esp32/lockfiles/dependencies.lock.esp322
-rw-r--r--ports/esp32/lockfiles/dependencies.lock.esp32c22
-rw-r--r--ports/esp32/lockfiles/dependencies.lock.esp32c32
-rw-r--r--ports/esp32/lockfiles/dependencies.lock.esp32c521
-rw-r--r--ports/esp32/lockfiles/dependencies.lock.esp32c62
-rw-r--r--ports/esp32/lockfiles/dependencies.lock.esp32s229
-rw-r--r--ports/esp32/lockfiles/dependencies.lock.esp32s329
-rw-r--r--ports/esp32/machine_adc.c7
-rw-r--r--ports/esp32/machine_bitstream.c141
-rw-r--r--ports/esp32/machine_i2c.c11
-rw-r--r--ports/esp32/machine_i2s.c2
-rw-r--r--ports/esp32/machine_pin.c7
-rw-r--r--ports/esp32/machine_pin.h26
-rw-r--r--ports/esp32/main.c14
-rw-r--r--ports/esp32/main/idf_component.yml7
-rw-r--r--ports/esp32/modesp32.h6
-rw-r--r--ports/esp32/modnetwork.h1
-rw-r--r--ports/esp32/mpconfigport.h26
-rw-r--r--ports/esp32/usb.c6
-rw-r--r--ports/esp32/usb.h2
-rw-r--r--ports/mimxrt/main.c4
-rw-r--r--ports/rp2/CMakeLists.txt21
-rwxr-xr-xports/rp2/boards/make-pins.py9
-rw-r--r--ports/rp2/boards/rp2040_af.csv (renamed from ports/rp2/boards/rp2_af.csv)0
-rw-r--r--ports/rp2/boards/rp2350_af.csv31
-rw-r--r--ports/rp2/boards/rp2350b_af.csv49
-rw-r--r--ports/rp2/machine_pin.c8
-rw-r--r--ports/rp2/main.c6
-rw-r--r--ports/rp2/pendsv.c2
-rw-r--r--ports/stm32/boards/NUCLEO_N657X0/mpconfigboard.h11
-rw-r--r--ports/stm32/boards/NUCLEO_N657X0/mpconfigboard.mk3
-rw-r--r--ports/stm32/boards/NUCLEO_N657X0/pins.csv11
-rw-r--r--ports/stm32/boards/OPENMV_N6/mpconfigboard.h18
-rw-r--r--ports/stm32/boards/OPENMV_N6/pins.csv13
-rw-r--r--ports/stm32/boards/stm32n657_af.csv17
-rw-r--r--ports/stm32/boards/stm32n6xx_hal_conf_base.h1
-rw-r--r--ports/stm32/eth.c489
-rw-r--r--ports/stm32/eth.h3
-rw-r--r--ports/stm32/eth_phy.c68
-rw-r--r--ports/stm32/eth_phy.h15
-rw-r--r--ports/stm32/lwip_inc/lwipopts.h11
-rw-r--r--ports/stm32/main.c7
-rw-r--r--ports/stm32/network_lan.c7
-rw-r--r--ports/stm32/powerctrlboot.c5
-rw-r--r--ports/unix/Makefile1
-rw-r--r--ports/unix/main.c134
-rw-r--r--ports/unix/mpconfigport.h6
-rw-r--r--ports/unix/mphalport.h7
-rw-r--r--ports/windows/Makefile1
-rw-r--r--ports/windows/micropython.vcxproj1
-rw-r--r--ports/windows/mpconfigport.h6
-rw-r--r--ports/zephyr/CMakeLists.txt22
-rw-r--r--ports/zephyr/README.md44
-rw-r--r--ports/zephyr/boards/rpi_pico.conf10
-rw-r--r--ports/zephyr/boards/rpi_pico.overlay14
-rw-r--r--ports/zephyr/modules/_boot.py36
-rw-r--r--ports/zephyr/modzephyr.c3
-rw-r--r--ports/zephyr/modzephyr.h4
-rw-r--r--ports/zephyr/mpconfigport.h5
-rw-r--r--ports/zephyr/zephyr_filesystem.c782
105 files changed, 2220 insertions, 597 deletions
diff --git a/ports/alif/tinyusb_port/alif_dcd_reg.h b/ports/alif/tinyusb_port/alif_dcd_reg.h
index 84220f6be..c5a707656 100644
--- a/ports/alif/tinyusb_port/alif_dcd_reg.h
+++ b/ports/alif/tinyusb_port/alif_dcd_reg.h
@@ -1,11 +1,13 @@
// *FORMAT-OFF*
-///-------------------------------------------------------------------------------------------------
-/// @file alif_dcd_reg.h
-/// @author karol.saja@alifsemi.com
-/// @version 0.0.1
-/// @date 2023-09-08
-/// @brief Low Level SPI driver
-///-------------------------------------------------------------------------------------------------
+/*
+ * Copyright (C) 2024 Alif Semiconductor - All Rights Reserved.
+ * Use, distribution and modification of this code is permitted under the
+ * terms stated in the Alif Semiconductor Software License Agreement
+ *
+ * You should have received a copy of the Alif Semiconductor Software
+ * License Agreement with this file. If not, please write to:
+ * contact@alifsemi.com, or visit: https://alifsemi.com/license
+ */
#ifndef __ALIF_DCD_REG_H__
#define __ALIF_DCD_REG_H__
diff --git a/ports/esp32/boards/ARDUINO_NANO_ESP32/mpconfigboard.cmake b/ports/esp32/boards/ARDUINO_NANO_ESP32/mpconfigboard.cmake
index a38888234..06d3c27a6 100644
--- a/ports/esp32/boards/ARDUINO_NANO_ESP32/mpconfigboard.cmake
+++ b/ports/esp32/boards/ARDUINO_NANO_ESP32/mpconfigboard.cmake
@@ -6,7 +6,6 @@ set(IDF_TARGET esp32s3)
set(SDKCONFIG_DEFAULTS
boards/sdkconfig.base
- boards/sdkconfig.usb
boards/sdkconfig.ble
boards/sdkconfig.240mhz
boards/sdkconfig.spiram_sx
diff --git a/ports/esp32/boards/ARDUINO_NANO_ESP32/mpconfigboard.h b/ports/esp32/boards/ARDUINO_NANO_ESP32/mpconfigboard.h
index 31b2a49bf..3ca587ae4 100644
--- a/ports/esp32/boards/ARDUINO_NANO_ESP32/mpconfigboard.h
+++ b/ports/esp32/boards/ARDUINO_NANO_ESP32/mpconfigboard.h
@@ -22,6 +22,11 @@
#define MICROPY_HW_USB_CDC_1200BPS_TOUCH (1)
#define MICROPY_SCHEDULER_STATIC_NODES (1)
+#define MICROPY_HW_USB_VID 0x2341
+#define MICROPY_HW_USB_PID 0x056B
+#define MICROPY_HW_USB_MANUFACTURER_STRING "Arduino"
+#define MICROPY_HW_USB_PRODUCT_FS_STRING "Nano ESP32"
+
#define MICROPY_BOARD_STARTUP NANO_ESP32_board_startup
void NANO_ESP32_board_startup(void);
diff --git a/ports/esp32/boards/ARDUINO_NANO_ESP32/sdkconfig.board b/ports/esp32/boards/ARDUINO_NANO_ESP32/sdkconfig.board
index d586dd4ce..242cff84d 100644
--- a/ports/esp32/boards/ARDUINO_NANO_ESP32/sdkconfig.board
+++ b/ports/esp32/boards/ARDUINO_NANO_ESP32/sdkconfig.board
@@ -11,13 +11,6 @@ CONFIG_SPIRAM_IGNORE_NOTFOUND=
CONFIG_LWIP_LOCAL_HOSTNAME="nano-esp32"
-CONFIG_TINYUSB_DESC_USE_ESPRESSIF_VID=n
-CONFIG_TINYUSB_DESC_USE_DEFAULT_PID=n
-CONFIG_TINYUSB_DESC_CUSTOM_VID=0x2341
-CONFIG_TINYUSB_DESC_CUSTOM_PID=0x056B
-CONFIG_TINYUSB_DESC_MANUFACTURER_STRING="Arduino"
-CONFIG_TINYUSB_DESC_PRODUCT_STRING="Nano ESP32"
-
# compatibility with Espressif Arduino core
CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP=y
CONFIG_ESP_ENABLE_COREDUMP_TO_FLASH=y
diff --git a/ports/esp32/boards/ESP32_GENERIC_C5/board.json b/ports/esp32/boards/ESP32_GENERIC_C5/board.json
new file mode 100644
index 000000000..371da3929
--- /dev/null
+++ b/ports/esp32/boards/ESP32_GENERIC_C5/board.json
@@ -0,0 +1,22 @@
+{
+ "deploy": [
+ "../deploy.md"
+ ],
+ "deploy_options": {
+ "flash_offset": "0x2000"
+ },
+ "docs": "",
+ "features": [
+ "BLE",
+ "External Flash",
+ "WiFi"
+ ],
+ "images": [
+ "esp32c5_devkitmini.jpg"
+ ],
+ "mcu": "esp32c5",
+ "product": "ESP32-C5",
+ "thumbnail": "",
+ "url": "https://www.espressif.com/en/products/modules",
+ "vendor": "Espressif"
+}
diff --git a/ports/esp32/boards/ESP32_GENERIC_C5/board.md b/ports/esp32/boards/ESP32_GENERIC_C5/board.md
new file mode 100644
index 000000000..82bac44b9
--- /dev/null
+++ b/ports/esp32/boards/ESP32_GENERIC_C5/board.md
@@ -0,0 +1,2 @@
+The following files are firmware images that should work on most ESP32-C5-based
+boards with at least 4MiB of flash and 40MHz/48MHz crystal frequency.
diff --git a/ports/esp32/boards/ESP32_GENERIC_C5/mpconfigboard.cmake b/ports/esp32/boards/ESP32_GENERIC_C5/mpconfigboard.cmake
new file mode 100644
index 000000000..79aba7d47
--- /dev/null
+++ b/ports/esp32/boards/ESP32_GENERIC_C5/mpconfigboard.cmake
@@ -0,0 +1,10 @@
+set(IDF_TARGET esp32c5)
+
+set(SDKCONFIG_DEFAULTS
+ boards/sdkconfig.base
+ boards/sdkconfig.riscv
+ boards/sdkconfig.ble
+ boards/sdkconfig.240mhz
+ boards/sdkconfig.free_ram
+ boards/ESP32_GENERIC_C5/sdkconfig.board
+)
diff --git a/ports/esp32/boards/ESP32_GENERIC_C5/mpconfigboard.h b/ports/esp32/boards/ESP32_GENERIC_C5/mpconfigboard.h
new file mode 100644
index 000000000..552468497
--- /dev/null
+++ b/ports/esp32/boards/ESP32_GENERIC_C5/mpconfigboard.h
@@ -0,0 +1,7 @@
+// This configuration is for a generic ESP32C5 board with 4MiB (or more) of flash.
+
+#define MICROPY_HW_BOARD_NAME "ESP32C5 module"
+#define MICROPY_HW_MCU_NAME "ESP32C5"
+
+#define MICROPY_PY_MACHINE_I2S (0)
+#define MICROPY_HW_ENABLE_UART_REPL (1)
diff --git a/ports/esp32/boards/ESP32_GENERIC_C5/sdkconfig.board b/ports/esp32/boards/ESP32_GENERIC_C5/sdkconfig.board
new file mode 100644
index 000000000..369330682
--- /dev/null
+++ b/ports/esp32/boards/ESP32_GENERIC_C5/sdkconfig.board
@@ -0,0 +1,2 @@
+CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
diff --git a/ports/esp32/boards/ESP32_GENERIC_S2/mpconfigboard.cmake b/ports/esp32/boards/ESP32_GENERIC_S2/mpconfigboard.cmake
index 76d185d90..6907adb81 100644
--- a/ports/esp32/boards/ESP32_GENERIC_S2/mpconfigboard.cmake
+++ b/ports/esp32/boards/ESP32_GENERIC_S2/mpconfigboard.cmake
@@ -2,6 +2,5 @@ set(IDF_TARGET esp32s2)
set(SDKCONFIG_DEFAULTS
boards/sdkconfig.base
- boards/sdkconfig.usb
boards/sdkconfig.spiram_sx
)
diff --git a/ports/esp32/boards/ESP32_GENERIC_S3/mpconfigboard.cmake b/ports/esp32/boards/ESP32_GENERIC_S3/mpconfigboard.cmake
index 9b0df3b37..cdcefed84 100644
--- a/ports/esp32/boards/ESP32_GENERIC_S3/mpconfigboard.cmake
+++ b/ports/esp32/boards/ESP32_GENERIC_S3/mpconfigboard.cmake
@@ -2,7 +2,6 @@ set(IDF_TARGET esp32s3)
set(SDKCONFIG_DEFAULTS
boards/sdkconfig.base
- boards/sdkconfig.usb
boards/sdkconfig.ble
boards/sdkconfig.spiram_sx
boards/ESP32_GENERIC_S3/sdkconfig.board
diff --git a/ports/esp32/boards/LOLIN_S2_MINI/mpconfigboard.cmake b/ports/esp32/boards/LOLIN_S2_MINI/mpconfigboard.cmake
index dc9abd747..8d6d1f359 100644
--- a/ports/esp32/boards/LOLIN_S2_MINI/mpconfigboard.cmake
+++ b/ports/esp32/boards/LOLIN_S2_MINI/mpconfigboard.cmake
@@ -3,7 +3,6 @@ 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)
diff --git a/ports/esp32/boards/LOLIN_S2_PICO/mpconfigboard.cmake b/ports/esp32/boards/LOLIN_S2_PICO/mpconfigboard.cmake
index dc9abd747..8d6d1f359 100644
--- a/ports/esp32/boards/LOLIN_S2_PICO/mpconfigboard.cmake
+++ b/ports/esp32/boards/LOLIN_S2_PICO/mpconfigboard.cmake
@@ -3,7 +3,6 @@ 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)
diff --git a/ports/esp32/boards/M5STACK_ATOMS3_LITE/mpconfigboard.cmake b/ports/esp32/boards/M5STACK_ATOMS3_LITE/mpconfigboard.cmake
index 10608fcec..9157c6b93 100644
--- a/ports/esp32/boards/M5STACK_ATOMS3_LITE/mpconfigboard.cmake
+++ b/ports/esp32/boards/M5STACK_ATOMS3_LITE/mpconfigboard.cmake
@@ -2,7 +2,6 @@ set(IDF_TARGET esp32s3)
set(SDKCONFIG_DEFAULTS
boards/sdkconfig.base
- boards/sdkconfig.usb
boards/sdkconfig.ble
boards/ESP32_GENERIC_S3/sdkconfig.board
)
diff --git a/ports/esp32/boards/UM_FEATHERS2/mpconfigboard.cmake b/ports/esp32/boards/UM_FEATHERS2/mpconfigboard.cmake
index 5e570d513..2d8f70135 100644
--- a/ports/esp32/boards/UM_FEATHERS2/mpconfigboard.cmake
+++ b/ports/esp32/boards/UM_FEATHERS2/mpconfigboard.cmake
@@ -2,7 +2,6 @@ set(IDF_TARGET esp32s2)
set(SDKCONFIG_DEFAULTS
boards/sdkconfig.base
boards/sdkconfig.spiram_sx
- boards/sdkconfig.usb
boards/UM_FEATHERS2/sdkconfig.board
)
diff --git a/ports/esp32/boards/UM_FEATHERS2NEO/mpconfigboard.cmake b/ports/esp32/boards/UM_FEATHERS2NEO/mpconfigboard.cmake
index c98ef6917..defb597c9 100644
--- a/ports/esp32/boards/UM_FEATHERS2NEO/mpconfigboard.cmake
+++ b/ports/esp32/boards/UM_FEATHERS2NEO/mpconfigboard.cmake
@@ -2,7 +2,6 @@ set(IDF_TARGET esp32s2)
set(SDKCONFIG_DEFAULTS
boards/sdkconfig.base
boards/sdkconfig.spiram_sx
- boards/sdkconfig.usb
boards/UM_FEATHERS2NEO/sdkconfig.board
)
diff --git a/ports/esp32/boards/UM_FEATHERS3/mpconfigboard.cmake b/ports/esp32/boards/UM_FEATHERS3/mpconfigboard.cmake
index 63d1af1da..5a41be186 100644
--- a/ports/esp32/boards/UM_FEATHERS3/mpconfigboard.cmake
+++ b/ports/esp32/boards/UM_FEATHERS3/mpconfigboard.cmake
@@ -2,7 +2,6 @@ set(IDF_TARGET esp32s3)
set(SDKCONFIG_DEFAULTS
boards/sdkconfig.base
- boards/sdkconfig.usb
boards/sdkconfig.ble
boards/sdkconfig.240mhz
boards/sdkconfig.spiram_sx
diff --git a/ports/esp32/boards/UM_FEATHERS3/mpconfigboard.h b/ports/esp32/boards/UM_FEATHERS3/mpconfigboard.h
index f4abfb21b..cb6269ff9 100644
--- a/ports/esp32/boards/UM_FEATHERS3/mpconfigboard.h
+++ b/ports/esp32/boards/UM_FEATHERS3/mpconfigboard.h
@@ -11,3 +11,8 @@
#define MICROPY_HW_SPI1_MOSI (35)
#define MICROPY_HW_SPI1_MISO (37)
#define MICROPY_HW_SPI1_SCK (36)
+
+#define MICROPY_HW_USB_VID 0x303A
+#define MICROPY_HW_USB_PID 0x80D7
+#define MICROPY_HW_USB_MANUFACTURER_STRING "Unexpected Maker"
+#define MICROPY_HW_USB_PRODUCT_FS_STRING "FeatherS3"
diff --git a/ports/esp32/boards/UM_FEATHERS3/sdkconfig.board b/ports/esp32/boards/UM_FEATHERS3/sdkconfig.board
index 3092e3559..2962cb44c 100644
--- a/ports/esp32/boards/UM_FEATHERS3/sdkconfig.board
+++ b/ports/esp32/boards/UM_FEATHERS3/sdkconfig.board
@@ -4,12 +4,3 @@ CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_SPIRAM_MEMTEST=
CONFIG_LWIP_LOCAL_HOSTNAME="UMFeatherS3"
-
-CONFIG_TINYUSB_DESC_CUSTOM_VID=0x303A
-CONFIG_TINYUSB_DESC_CUSTOM_PID=0x80D7
-CONFIG_TINYUSB_DESC_BCD_DEVICE=0x0100
-CONFIG_TINYUSB_DESC_USE_ESPRESSIF_VID=n
-CONFIG_TINYUSB_DESC_USE_DEFAULT_PID=n
-CONFIG_TINYUSB_DESC_MANUFACTURER_STRING="Unexpected Maker"
-CONFIG_TINYUSB_DESC_PRODUCT_STRING="FeatherS3"
-CONFIG_TINYUSB_DESC_SERIAL_STRING="_fs3_"
diff --git a/ports/esp32/boards/UM_FEATHERS3NEO/mpconfigboard.cmake b/ports/esp32/boards/UM_FEATHERS3NEO/mpconfigboard.cmake
index 1d2b887d2..698aa76f0 100644
--- a/ports/esp32/boards/UM_FEATHERS3NEO/mpconfigboard.cmake
+++ b/ports/esp32/boards/UM_FEATHERS3NEO/mpconfigboard.cmake
@@ -2,7 +2,6 @@ set(IDF_TARGET esp32s3)
set(SDKCONFIG_DEFAULTS
boards/sdkconfig.base
- boards/sdkconfig.usb
boards/sdkconfig.ble
boards/sdkconfig.240mhz
boards/sdkconfig.spiram_sx
diff --git a/ports/esp32/boards/UM_FEATHERS3NEO/mpconfigboard.h b/ports/esp32/boards/UM_FEATHERS3NEO/mpconfigboard.h
index c08206f7b..bfe38bc03 100644
--- a/ports/esp32/boards/UM_FEATHERS3NEO/mpconfigboard.h
+++ b/ports/esp32/boards/UM_FEATHERS3NEO/mpconfigboard.h
@@ -8,3 +8,8 @@
#define MICROPY_HW_SPI1_MOSI (35)
#define MICROPY_HW_SPI1_MISO (37)
#define MICROPY_HW_SPI1_SCK (36)
+
+#define MICROPY_HW_USB_VID 0x303A
+#define MICROPY_HW_USB_PID 0x81FC
+#define MICROPY_HW_USB_MANUFACTURER_STRING "Unexpected Maker"
+#define MICROPY_HW_USB_PRODUCT_FS_STRING "FeatherS3 Neo"
diff --git a/ports/esp32/boards/UM_FEATHERS3NEO/sdkconfig.board b/ports/esp32/boards/UM_FEATHERS3NEO/sdkconfig.board
index 25b8d7689..8d44c65c3 100644
--- a/ports/esp32/boards/UM_FEATHERS3NEO/sdkconfig.board
+++ b/ports/esp32/boards/UM_FEATHERS3NEO/sdkconfig.board
@@ -5,12 +5,3 @@ CONFIG_ESPTOOLPY_AFTER_NORESET=y
CONFIG_SPIRAM_MEMTEST=
CONFIG_LWIP_LOCAL_HOSTNAME="UMFeatherS3Neo"
-
-CONFIG_TINYUSB_DESC_CUSTOM_VID=0x303A
-CONFIG_TINYUSB_DESC_CUSTOM_PID=0x81FC
-CONFIG_TINYUSB_DESC_BCD_DEVICE=0x0100
-CONFIG_TINYUSB_DESC_USE_ESPRESSIF_VID=n
-CONFIG_TINYUSB_DESC_USE_DEFAULT_PID=n
-CONFIG_TINYUSB_DESC_MANUFACTURER_STRING="Unexpected Maker"
-CONFIG_TINYUSB_DESC_PRODUCT_STRING="FeatherS3 Neo"
-CONFIG_TINYUSB_DESC_SERIAL_STRING="_fs3neo_"
diff --git a/ports/esp32/boards/UM_NANOS3/mpconfigboard.cmake b/ports/esp32/boards/UM_NANOS3/mpconfigboard.cmake
index 6c7f34009..3935a66f8 100644
--- a/ports/esp32/boards/UM_NANOS3/mpconfigboard.cmake
+++ b/ports/esp32/boards/UM_NANOS3/mpconfigboard.cmake
@@ -2,7 +2,6 @@ set(IDF_TARGET esp32s3)
set(SDKCONFIG_DEFAULTS
boards/sdkconfig.base
- boards/sdkconfig.usb
boards/sdkconfig.ble
boards/sdkconfig.240mhz
boards/sdkconfig.spiram_sx
diff --git a/ports/esp32/boards/UM_NANOS3/mpconfigboard.h b/ports/esp32/boards/UM_NANOS3/mpconfigboard.h
index 44197be2a..44434d26e 100644
--- a/ports/esp32/boards/UM_NANOS3/mpconfigboard.h
+++ b/ports/esp32/boards/UM_NANOS3/mpconfigboard.h
@@ -8,3 +8,8 @@
#define MICROPY_HW_SPI1_MOSI (35)
#define MICROPY_HW_SPI1_MISO (37)
#define MICROPY_HW_SPI1_SCK (36)
+
+#define MICROPY_HW_USB_VID 0x303A
+#define MICROPY_HW_USB_PID 0x817A
+#define MICROPY_HW_USB_MANUFACTURER_STRING "Unexpected Maker"
+#define MICROPY_HW_USB_PRODUCT_FS_STRING "NanoS3"
diff --git a/ports/esp32/boards/UM_NANOS3/sdkconfig.board b/ports/esp32/boards/UM_NANOS3/sdkconfig.board
index e06f7a424..0a1361b9b 100644
--- a/ports/esp32/boards/UM_NANOS3/sdkconfig.board
+++ b/ports/esp32/boards/UM_NANOS3/sdkconfig.board
@@ -4,12 +4,3 @@ CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_SPIRAM_MEMTEST=
CONFIG_LWIP_LOCAL_HOSTNAME="UMNanoS3"
-
-CONFIG_TINYUSB_DESC_CUSTOM_VID=0x303A
-CONFIG_TINYUSB_DESC_CUSTOM_PID=0x817A
-CONFIG_TINYUSB_DESC_BCD_DEVICE=0x0100
-CONFIG_TINYUSB_DESC_USE_ESPRESSIF_VID=n
-CONFIG_TINYUSB_DESC_USE_DEFAULT_PID=n
-CONFIG_TINYUSB_DESC_MANUFACTURER_STRING="Unexpected Maker"
-CONFIG_TINYUSB_DESC_PRODUCT_STRING="NanoS3"
-CONFIG_TINYUSB_DESC_SERIAL_STRING="_ns3_"
diff --git a/ports/esp32/boards/UM_OMGS3/mpconfigboard.cmake b/ports/esp32/boards/UM_OMGS3/mpconfigboard.cmake
index aa82111d7..85c3d71e8 100644
--- a/ports/esp32/boards/UM_OMGS3/mpconfigboard.cmake
+++ b/ports/esp32/boards/UM_OMGS3/mpconfigboard.cmake
@@ -2,7 +2,6 @@ set(IDF_TARGET esp32s3)
set(SDKCONFIG_DEFAULTS
boards/sdkconfig.base
- boards/sdkconfig.usb
boards/sdkconfig.ble
boards/sdkconfig.240mhz
boards/sdkconfig.spiram_sx
diff --git a/ports/esp32/boards/UM_OMGS3/mpconfigboard.h b/ports/esp32/boards/UM_OMGS3/mpconfigboard.h
index e3955a6b8..451225b6f 100644
--- a/ports/esp32/boards/UM_OMGS3/mpconfigboard.h
+++ b/ports/esp32/boards/UM_OMGS3/mpconfigboard.h
@@ -8,3 +8,8 @@
#define MICROPY_HW_SPI1_MOSI (6)
#define MICROPY_HW_SPI1_MISO (5)
#define MICROPY_HW_SPI1_SCK (4)
+
+#define MICROPY_HW_USB_VID 0x303A
+#define MICROPY_HW_USB_PID 0x8225
+#define MICROPY_HW_USB_MANUFACTURER_STRING "Unexpected Maker"
+#define MICROPY_HW_USB_PRODUCT_FS_STRING "OMGS3"
diff --git a/ports/esp32/boards/UM_OMGS3/sdkconfig.board b/ports/esp32/boards/UM_OMGS3/sdkconfig.board
index 8a0bf0b13..794bc70b1 100644
--- a/ports/esp32/boards/UM_OMGS3/sdkconfig.board
+++ b/ports/esp32/boards/UM_OMGS3/sdkconfig.board
@@ -5,12 +5,3 @@ CONFIG_ESPTOOLPY_AFTER_NORESET=y
CONFIG_SPIRAM_MEMTEST=
CONFIG_LWIP_LOCAL_HOSTNAME="UMOMGS3"
-
-CONFIG_TINYUSB_DESC_CUSTOM_VID=0x303A
-CONFIG_TINYUSB_DESC_CUSTOM_PID=0x8225
-CONFIG_TINYUSB_DESC_BCD_DEVICE=0x0100
-CONFIG_TINYUSB_DESC_USE_ESPRESSIF_VID=n
-CONFIG_TINYUSB_DESC_USE_DEFAULT_PID=n
-CONFIG_TINYUSB_DESC_MANUFACTURER_STRING="Unexpected Maker"
-CONFIG_TINYUSB_DESC_PRODUCT_STRING="OMGS3"
-CONFIG_TINYUSB_DESC_SERIAL_STRING="_omgs3_"
diff --git a/ports/esp32/boards/UM_PROS3/mpconfigboard.cmake b/ports/esp32/boards/UM_PROS3/mpconfigboard.cmake
index 41a96f26e..c8267f728 100644
--- a/ports/esp32/boards/UM_PROS3/mpconfigboard.cmake
+++ b/ports/esp32/boards/UM_PROS3/mpconfigboard.cmake
@@ -2,7 +2,6 @@ set(IDF_TARGET esp32s3)
set(SDKCONFIG_DEFAULTS
boards/sdkconfig.base
- boards/sdkconfig.usb
boards/sdkconfig.ble
boards/sdkconfig.240mhz
boards/sdkconfig.spiram_sx
diff --git a/ports/esp32/boards/UM_PROS3/mpconfigboard.h b/ports/esp32/boards/UM_PROS3/mpconfigboard.h
index cc0ebbefa..eea6f6e65 100644
--- a/ports/esp32/boards/UM_PROS3/mpconfigboard.h
+++ b/ports/esp32/boards/UM_PROS3/mpconfigboard.h
@@ -8,3 +8,8 @@
#define MICROPY_HW_SPI1_MOSI (35)
#define MICROPY_HW_SPI1_MISO (37)
#define MICROPY_HW_SPI1_SCK (36)
+
+#define MICROPY_HW_USB_VID 0x303A
+#define MICROPY_HW_USB_PID 0x80D4
+#define MICROPY_HW_USB_MANUFACTURER_STRING "Unexpected Maker"
+#define MICROPY_HW_USB_PRODUCT_FS_STRING "ProS3"
diff --git a/ports/esp32/boards/UM_PROS3/sdkconfig.board b/ports/esp32/boards/UM_PROS3/sdkconfig.board
index 75ca58d80..1b10ba11c 100644
--- a/ports/esp32/boards/UM_PROS3/sdkconfig.board
+++ b/ports/esp32/boards/UM_PROS3/sdkconfig.board
@@ -4,12 +4,3 @@ CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_SPIRAM_MEMTEST=
CONFIG_LWIP_LOCAL_HOSTNAME="UMProS3"
-
-CONFIG_TINYUSB_DESC_CUSTOM_VID=0x303A
-CONFIG_TINYUSB_DESC_CUSTOM_PID=0x80D4
-CONFIG_TINYUSB_DESC_BCD_DEVICE=0x0100
-CONFIG_TINYUSB_DESC_USE_ESPRESSIF_VID=n
-CONFIG_TINYUSB_DESC_USE_DEFAULT_PID=n
-CONFIG_TINYUSB_DESC_MANUFACTURER_STRING="Unexpected Maker"
-CONFIG_TINYUSB_DESC_PRODUCT_STRING="ProS3"
-CONFIG_TINYUSB_DESC_SERIAL_STRING="_ps3_"
diff --git a/ports/esp32/boards/UM_RGBTOUCH_MINI/mpconfigboard.cmake b/ports/esp32/boards/UM_RGBTOUCH_MINI/mpconfigboard.cmake
index 8b29cb344..4686fc588 100644
--- a/ports/esp32/boards/UM_RGBTOUCH_MINI/mpconfigboard.cmake
+++ b/ports/esp32/boards/UM_RGBTOUCH_MINI/mpconfigboard.cmake
@@ -2,7 +2,6 @@ set(IDF_TARGET esp32s3)
set(SDKCONFIG_DEFAULTS
boards/sdkconfig.base
- boards/sdkconfig.usb
boards/sdkconfig.ble
boards/sdkconfig.240mhz
boards/sdkconfig.spiram_sx
diff --git a/ports/esp32/boards/UM_RGBTOUCH_MINI/mpconfigboard.h b/ports/esp32/boards/UM_RGBTOUCH_MINI/mpconfigboard.h
index 118412479..2d83cba16 100644
--- a/ports/esp32/boards/UM_RGBTOUCH_MINI/mpconfigboard.h
+++ b/ports/esp32/boards/UM_RGBTOUCH_MINI/mpconfigboard.h
@@ -8,3 +8,8 @@
#define MICROPY_HW_SPI1_MOSI (35)
#define MICROPY_HW_SPI1_MISO (37)
#define MICROPY_HW_SPI1_SCK (36)
+
+#define MICROPY_HW_USB_VID 0x303A
+#define MICROPY_HW_USB_PID 0x81FF
+#define MICROPY_HW_USB_MANUFACTURER_STRING "Unexpected Maker"
+#define MICROPY_HW_USB_PRODUCT_FS_STRING "RGBTouchMini"
diff --git a/ports/esp32/boards/UM_RGBTOUCH_MINI/sdkconfig.board b/ports/esp32/boards/UM_RGBTOUCH_MINI/sdkconfig.board
index 7d244fdc1..234aed6b2 100644
--- a/ports/esp32/boards/UM_RGBTOUCH_MINI/sdkconfig.board
+++ b/ports/esp32/boards/UM_RGBTOUCH_MINI/sdkconfig.board
@@ -5,12 +5,3 @@ CONFIG_ESPTOOLPY_AFTER_NORESET=y
CONFIG_SPIRAM_MEMTEST=
CONFIG_LWIP_LOCAL_HOSTNAME="UMRGBTouchMini"
-
-CONFIG_TINYUSB_DESC_CUSTOM_VID=0x303A
-CONFIG_TINYUSB_DESC_CUSTOM_PID=0x81FF
-CONFIG_TINYUSB_DESC_BCD_DEVICE=0x0100
-CONFIG_TINYUSB_DESC_USE_ESPRESSIF_VID=n
-CONFIG_TINYUSB_DESC_USE_DEFAULT_PID=n
-CONFIG_TINYUSB_DESC_MANUFACTURER_STRING="Unexpected Maker"
-CONFIG_TINYUSB_DESC_PRODUCT_STRING="RGBTouchMini"
-CONFIG_TINYUSB_DESC_SERIAL_STRING="_rgbtouch_mini_"
diff --git a/ports/esp32/boards/UM_TINYS2/mpconfigboard.cmake b/ports/esp32/boards/UM_TINYS2/mpconfigboard.cmake
index 70cb4a814..4b0c6bfcc 100644
--- a/ports/esp32/boards/UM_TINYS2/mpconfigboard.cmake
+++ b/ports/esp32/boards/UM_TINYS2/mpconfigboard.cmake
@@ -2,7 +2,6 @@ set(IDF_TARGET esp32s2)
set(SDKCONFIG_DEFAULTS
boards/sdkconfig.base
boards/sdkconfig.spiram_sx
- boards/sdkconfig.usb
boards/UM_TINYS2/sdkconfig.board
)
diff --git a/ports/esp32/boards/UM_TINYS3/mpconfigboard.cmake b/ports/esp32/boards/UM_TINYS3/mpconfigboard.cmake
index 6c7f34009..3935a66f8 100644
--- a/ports/esp32/boards/UM_TINYS3/mpconfigboard.cmake
+++ b/ports/esp32/boards/UM_TINYS3/mpconfigboard.cmake
@@ -2,7 +2,6 @@ set(IDF_TARGET esp32s3)
set(SDKCONFIG_DEFAULTS
boards/sdkconfig.base
- boards/sdkconfig.usb
boards/sdkconfig.ble
boards/sdkconfig.240mhz
boards/sdkconfig.spiram_sx
diff --git a/ports/esp32/boards/UM_TINYS3/mpconfigboard.h b/ports/esp32/boards/UM_TINYS3/mpconfigboard.h
index 74c7622cb..2cba3f1b0 100644
--- a/ports/esp32/boards/UM_TINYS3/mpconfigboard.h
+++ b/ports/esp32/boards/UM_TINYS3/mpconfigboard.h
@@ -8,3 +8,8 @@
#define MICROPY_HW_SPI1_MOSI (35)
#define MICROPY_HW_SPI1_MISO (37)
#define MICROPY_HW_SPI1_SCK (36)
+
+#define MICROPY_HW_USB_VID 0x303A
+#define MICROPY_HW_USB_PID 0x80D1
+#define MICROPY_HW_USB_MANUFACTURER_STRING "Unexpected Maker"
+#define MICROPY_HW_USB_PRODUCT_FS_STRING "TinyS3"
diff --git a/ports/esp32/boards/UM_TINYS3/sdkconfig.board b/ports/esp32/boards/UM_TINYS3/sdkconfig.board
index 2474c5fb2..b9cb80695 100644
--- a/ports/esp32/boards/UM_TINYS3/sdkconfig.board
+++ b/ports/esp32/boards/UM_TINYS3/sdkconfig.board
@@ -4,12 +4,3 @@ CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_SPIRAM_MEMTEST=
CONFIG_LWIP_LOCAL_HOSTNAME="UMTinyS3"
-
-CONFIG_TINYUSB_DESC_CUSTOM_VID=0x303A
-CONFIG_TINYUSB_DESC_CUSTOM_PID=0x80D1
-CONFIG_TINYUSB_DESC_BCD_DEVICE=0x0100
-CONFIG_TINYUSB_DESC_USE_ESPRESSIF_VID=n
-CONFIG_TINYUSB_DESC_USE_DEFAULT_PID=n
-CONFIG_TINYUSB_DESC_MANUFACTURER_STRING="Unexpected Maker"
-CONFIG_TINYUSB_DESC_PRODUCT_STRING="TinyS3"
-CONFIG_TINYUSB_DESC_SERIAL_STRING="_ts3_"
diff --git a/ports/esp32/boards/UM_TINYWATCHS3/mpconfigboard.cmake b/ports/esp32/boards/UM_TINYWATCHS3/mpconfigboard.cmake
index 089149c44..2978dcd6f 100644
--- a/ports/esp32/boards/UM_TINYWATCHS3/mpconfigboard.cmake
+++ b/ports/esp32/boards/UM_TINYWATCHS3/mpconfigboard.cmake
@@ -2,7 +2,6 @@ set(IDF_TARGET esp32s3)
set(SDKCONFIG_DEFAULTS
boards/sdkconfig.base
- boards/sdkconfig.usb
boards/sdkconfig.ble
boards/sdkconfig.240mhz
boards/sdkconfig.spiram_sx
diff --git a/ports/esp32/boards/UM_TINYWATCHS3/mpconfigboard.h b/ports/esp32/boards/UM_TINYWATCHS3/mpconfigboard.h
index 6cc134541..c8fc554a1 100644
--- a/ports/esp32/boards/UM_TINYWATCHS3/mpconfigboard.h
+++ b/ports/esp32/boards/UM_TINYWATCHS3/mpconfigboard.h
@@ -8,3 +8,8 @@
#define MICROPY_HW_SPI1_MOSI (35)
#define MICROPY_HW_SPI1_MISO (37)
#define MICROPY_HW_SPI1_SCK (36)
+
+#define MICROPY_HW_USB_VID 0x303A
+#define MICROPY_HW_USB_PID 0x81B1
+#define MICROPY_HW_USB_MANUFACTURER_STRING "Unexpected Maker"
+#define MICROPY_HW_USB_PRODUCT_FS_STRING "TinyWATCHS3"
diff --git a/ports/esp32/boards/UM_TINYWATCHS3/sdkconfig.board b/ports/esp32/boards/UM_TINYWATCHS3/sdkconfig.board
index 10121d235..da804fe30 100644
--- a/ports/esp32/boards/UM_TINYWATCHS3/sdkconfig.board
+++ b/ports/esp32/boards/UM_TINYWATCHS3/sdkconfig.board
@@ -4,12 +4,3 @@ CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_SPIRAM_MEMTEST=
CONFIG_LWIP_LOCAL_HOSTNAME="UMTinyWATCHS3"
-
-CONFIG_TINYUSB_DESC_CUSTOM_VID=0x303A
-CONFIG_TINYUSB_DESC_CUSTOM_PID=0x81B1
-CONFIG_TINYUSB_DESC_BCD_DEVICE=0x0100
-CONFIG_TINYUSB_DESC_USE_ESPRESSIF_VID=n
-CONFIG_TINYUSB_DESC_USE_DEFAULT_PID=n
-CONFIG_TINYUSB_DESC_MANUFACTURER_STRING="Unexpected Maker"
-CONFIG_TINYUSB_DESC_PRODUCT_STRING="TinyWATCHS3"
-CONFIG_TINYUSB_DESC_SERIAL_STRING="_tws3_"
diff --git a/ports/esp32/boards/sdkconfig.base b/ports/esp32/boards/sdkconfig.base
index e1b30b8e5..6c8368ac4 100644
--- a/ports/esp32/boards/sdkconfig.base
+++ b/ports/esp32/boards/sdkconfig.base
@@ -124,7 +124,6 @@ CONFIG_UART_ISR_IN_IRAM=y
# IDF 5 deprecated
CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN=y
-CONFIG_RMT_SUPPRESS_DEPRECATE_WARN=y
CONFIG_TOUCH_SUPPRESS_DEPRECATE_WARN=y
CONFIG_ETH_USE_SPI_ETHERNET=y
diff --git a/ports/esp32/boards/sdkconfig.usb b/ports/esp32/boards/sdkconfig.usb
deleted file mode 100644
index 4090c710e..000000000
--- a/ports/esp32/boards/sdkconfig.usb
+++ /dev/null
@@ -1,4 +0,0 @@
-CONFIG_USB_OTG_SUPPORTED=y
-CONFIG_TINYUSB_CDC_ENABLED=y
-CONFIG_TINYUSB_CDC_RX_BUFSIZE=256
-CONFIG_TINYUSB_CDC_TX_BUFSIZE=256
diff --git a/ports/esp32/esp32_common.cmake b/ports/esp32/esp32_common.cmake
index 79a60adac..807d71283 100644
--- a/ports/esp32/esp32_common.cmake
+++ b/ports/esp32/esp32_common.cmake
@@ -97,6 +97,14 @@ if(MICROPY_PY_TINYUSB)
list(APPEND MICROPY_INC_TINYUSB
${MICROPY_DIR}/shared/tinyusb/
)
+
+ # Build the Espressif tinyusb component with MicroPython shared/tinyusb/tusb_config.h
+ idf_component_get_property(tusb_lib espressif__tinyusb COMPONENT_LIB)
+ target_include_directories(${tusb_lib} PRIVATE
+ ${MICROPY_DIR}/shared/tinyusb
+ ${MICROPY_DIR}
+ ${MICROPY_PORT_DIR}
+ ${MICROPY_BOARD_DIR})
endif()
list(APPEND MICROPY_SOURCE_PORT
@@ -262,6 +270,14 @@ target_compile_options(${MICROPY_TARGET} PUBLIC
target_include_directories(${MICROPY_TARGET} PUBLIC
${IDF_PATH}/components/bt/host/nimble/nimble
)
+if (IDF_VERSION VERSION_LESS "5.3")
+# Additional include directories needed for private RMT header.
+# IDF 5.x versions before 5.3.1
+ message(STATUS "Using private rmt headers for ${IDF_VERSION}")
+ target_include_directories(${MICROPY_TARGET} PRIVATE
+ ${IDF_PATH}/components/driver/rmt
+ )
+endif()
# Add additional extmod and usermod components.
if (MICROPY_PY_BTREE)
diff --git a/ports/esp32/esp32_rmt.c b/ports/esp32/esp32_rmt.c
index f3bfbecdd..85a98c291 100644
--- a/ports/esp32/esp32_rmt.c
+++ b/ports/esp32/esp32_rmt.c
@@ -4,6 +4,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2019 "Matt Trentini" <matt.trentini@gmail.com>
+ * Copyright (c) 2024 "Elvis Pfützenreuter" <elvis.pfutzenreuter@gmail.com>
*
* 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,13 +27,16 @@
#include "py/mphal.h"
#include "py/runtime.h"
+#include "py/stream.h"
#include "modmachine.h"
#include "modesp32.h"
#include "esp_task.h"
#if SOC_RMT_SUPPORTED
-#include "driver/rmt.h"
+#include "esp_clk_tree.h"
+#include "driver/rmt_tx.h"
+#include "driver/rmt_encoder.h"
// This exposes the ESP32's RMT module to MicroPython. RMT is provided by the Espressif ESP-IDF:
//
@@ -46,105 +50,101 @@
// Originally designed to generate infrared remote control signals, the module is very
// flexible and quite easy-to-use.
//
-// This current MicroPython implementation lacks some major features, notably receive pulses
-// and carrier output.
-
-// Last available RMT channel that can transmit.
-#define RMT_LAST_TX_CHANNEL (SOC_RMT_TX_CANDIDATES_PER_GROUP - 1)
+// This code exposes the RMT TX feature.
// Forward declaration
extern const mp_obj_type_t esp32_rmt_type;
typedef struct _esp32_rmt_obj_t {
mp_obj_base_t base;
- uint8_t channel_id;
+ rmt_channel_handle_t channel;
+ bool enabled;
gpio_num_t pin;
- uint8_t clock_div;
- mp_uint_t num_items;
- rmt_item32_t *items;
- bool loop_en;
+ uint32_t clock_freq;
+ int resolution_hz;
+ mp_uint_t cap_items;
+ rmt_symbol_word_t *items;
+ int loop_count;
+ int tx_ongoing;
+
+ rmt_encoder_handle_t encoder;
+ mp_uint_t idle_level;
} esp32_rmt_obj_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_LAST_TX_CHANNEL;
-
-#if MP_TASK_COREID == 0
-
-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;
-}
-
-#else
+// Decide RMT usage in the machine_bitstream_high_low_rmt implementation.
+bool esp32_rmt_bitstream_enabled = true;
-// MicroPython runs on core 1, so we can call the RMT installer directly and its
-// interrupt handler will also run on core 1.
-esp_err_t rmt_driver_install_core1(uint8_t channel_id) {
- return rmt_driver_install(channel_id, 0, 0);
+static bool IRAM_ATTR esp32_rmt_tx_trans_done(rmt_channel_handle_t channel, const rmt_tx_done_event_data_t *edata, void *user_ctx) {
+ esp32_rmt_obj_t *self = user_ctx;
+ self->tx_ongoing -= 1;
+ return false;
}
-#endif // MP_TASK_COREID==0
-
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} },
+ { MP_QSTR_id, MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
- { MP_QSTR_clock_div, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, // 100ns resolution
+ { MP_QSTR_resolution_hz, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_clock_div, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_idle_level, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, // low voltage
{ MP_QSTR_tx_carrier, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // no carrier
+ { MP_QSTR_num_symbols, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SOC_RMT_MEM_WORDS_PER_CHANNEL} },
};
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);
- mp_uint_t channel_id = args[0].u_int;
+ // RMT channel is an opaque struct in current RMT API and channel_id is a dummy parameter
+ // mp_uint_t channel_id = args[0].u_int;
gpio_num_t pin_id = machine_pin_get_id(args[1].u_obj);
- mp_uint_t clock_div = args[2].u_int;
- mp_uint_t idle_level = args[3].u_bool;
- mp_obj_t tx_carrier_obj = args[4].u_obj;
- if (esp32_rmt_bitstream_channel_id >= 0 && channel_id == esp32_rmt_bitstream_channel_id) {
- mp_raise_ValueError(MP_ERROR_TEXT("channel used by bitstream"));
+ uint32_t clock_freq;
+ check_esp_err(esp_clk_tree_src_get_freq_hz(RMT_CLK_SRC_DEFAULT, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clock_freq));
+
+ mp_uint_t resolution_hz;
+ if (args[2].u_obj != mp_const_none && args[3].u_obj != mp_const_none) {
+ mp_raise_ValueError(MP_ERROR_TEXT("resolution_hz and clock_div are mutually exclusive"));
+ } else if (args[2].u_obj == mp_const_none && args[3].u_obj == mp_const_none) {
+ // default value
+ resolution_hz = 10000000;
+ } else if (args[2].u_obj != mp_const_none) {
+ resolution_hz = mp_obj_get_int(args[2].u_obj);
+ if (resolution_hz <= 0) {
+ mp_raise_ValueError(MP_ERROR_TEXT("resolution_hz must be positive"));
+ }
+ } else if (args[3].u_obj != mp_const_none) {
+ mp_uint_t clock_div = mp_obj_get_int(args[3].u_obj);
+ if (clock_div < 1 || clock_div > 255) {
+ mp_raise_ValueError(MP_ERROR_TEXT("clock_div must be between 1 and 255"));
+ }
+ resolution_hz = clock_freq / clock_div;
}
- if (clock_div < 1 || clock_div > 255) {
- mp_raise_ValueError(MP_ERROR_TEXT("clock_div must be between 1 and 255"));
+ mp_uint_t idle_level = args[4].u_bool;
+ mp_obj_t tx_carrier_obj = args[5].u_obj;
+ mp_uint_t num_symbols = args[6].u_int;
+
+ if (num_symbols < SOC_RMT_MEM_WORDS_PER_CHANNEL || ((num_symbols % 2) == 1)) {
+ mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("num_symbols must be even and at least %d"), SOC_RMT_MEM_WORDS_PER_CHANNEL);
}
esp32_rmt_obj_t *self = mp_obj_malloc_with_finaliser(esp32_rmt_obj_t, &esp32_rmt_type);
- self->channel_id = channel_id;
+ self->channel = NULL;
self->pin = pin_id;
- self->clock_div = clock_div;
- self->loop_en = false;
+ self->clock_freq = clock_freq;
+ self->resolution_hz = resolution_hz;
+ self->loop_count = 0;
+ self->tx_ongoing = 0;
+ self->idle_level = idle_level;
+ self->enabled = false;
+
+ rmt_tx_channel_config_t tx_chan_config = {
+ .clk_src = RMT_CLK_SRC_DEFAULT,
+ .gpio_num = self->pin,
+ .mem_block_symbols = num_symbols,
+ .resolution_hz = resolution_hz,
+ .trans_queue_depth = 4,
+ };
- rmt_config_t config = {0};
- config.rmt_mode = RMT_MODE_TX;
- config.channel = (rmt_channel_t)self->channel_id;
- config.gpio_num = self->pin;
- config.mem_block_num = 1;
- config.tx_config.loop_en = 0;
+ check_esp_err(rmt_new_tx_channel(&tx_chan_config, &self->channel));
if (tx_carrier_obj != mp_const_none) {
mp_obj_t *tx_carrier_details = NULL;
@@ -160,21 +160,21 @@ static mp_obj_t esp32_rmt_make_new(const mp_obj_type_t *type, size_t n_args, siz
mp_raise_ValueError(MP_ERROR_TEXT("tx_carrier duty must be 0..100"));
}
- config.tx_config.carrier_en = 1;
- config.tx_config.carrier_freq_hz = frequency;
- config.tx_config.carrier_duty_percent = duty;
- config.tx_config.carrier_level = level;
- } else {
- config.tx_config.carrier_en = 0;
+ rmt_carrier_config_t tx_carrier_cfg = {
+ .duty_cycle = ((float)duty) / 100.0,
+ .frequency_hz = frequency,
+ .flags.polarity_active_low = !level,
+ };
+ check_esp_err(rmt_apply_carrier(self->channel, &tx_carrier_cfg));
}
- config.tx_config.idle_output_en = 1;
- config.tx_config.idle_level = idle_level;
-
- config.clk_div = self->clock_div;
+ rmt_copy_encoder_config_t copy_encoder_config = {};
+ check_esp_err(rmt_new_copy_encoder(&copy_encoder_config, &self->encoder));
- check_esp_err(rmt_config(&config));
- check_esp_err(rmt_driver_install_core1(config.channel));
+ rmt_tx_event_callbacks_t callbacks = {
+ .on_trans_done = esp32_rmt_tx_trans_done,
+ };
+ check_esp_err(rmt_tx_register_event_callbacks(self->channel, &callbacks, self));
return MP_OBJ_FROM_PTR(self);
}
@@ -182,33 +182,72 @@ static mp_obj_t esp32_rmt_make_new(const mp_obj_type_t *type, size_t n_args, siz
static void esp32_rmt_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
esp32_rmt_obj_t *self = MP_OBJ_TO_PTR(self_in);
if (self->pin != -1) {
- bool idle_output_en;
- rmt_idle_level_t idle_level;
- check_esp_err(rmt_get_idle_level(self->channel_id, &idle_output_en, &idle_level));
- mp_printf(print, "RMT(channel=%u, pin=%u, source_freq=%u, clock_div=%u, idle_level=%u)",
- self->channel_id, self->pin, APB_CLK_FREQ, self->clock_div, idle_level);
+ mp_printf(print, "RMT(pin=%u, source_freq=%u, resolution_hz=%u, idle_level=%u)",
+ self->pin, self->clock_freq, self->resolution_hz, self->idle_level);
} else {
mp_printf(print, "RMT()");
}
}
+static void esp32_rmt_deactivate(esp32_rmt_obj_t *self) {
+ if (self->enabled) {
+ // FIXME: panics in ESP32 if called while TX is ongoing and TX sequence is long (>300ms)
+ // Does not panic in ESP32-S3, ESP32-C3 and ESP32-C6.
+ // Tested with ESP-IDF up to 5.5
+ // ESP-IDF issue: https://github.com/espressif/esp-idf/issues/17692
+ //
+ // Cause is Interrupt WDT to trigger because ESP-IDF rmt_disable() disables
+ // interrupts and spinlocks until the ongoing TX sequence is finished.
+ //
+ // Workaround is never try to stop RMT sequences longer than 300ms (which are unusual
+ // anyway). Or apply the patch mentioned at the GitHub issue to ESP-IDF.
+ rmt_disable(self->channel);
+ self->enabled = false;
+ }
+}
+
+static mp_obj_t esp32_rmt_active(size_t n_args, const mp_obj_t *args) {
+ esp32_rmt_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+
+ if (n_args == 1) {
+ return mp_obj_new_bool(self->enabled && self->tx_ongoing > 0);
+ } else if (mp_obj_is_true(args[1])) {
+ mp_raise_ValueError(MP_ERROR_TEXT("activate by calling write_pulses()"));
+ }
+
+ esp32_rmt_deactivate(self);
+
+ return mp_const_false;
+}
+static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_rmt_active_obj, 1, 2, esp32_rmt_active);
+
static mp_obj_t esp32_rmt_deinit(mp_obj_t self_in) {
- // fixme: check for valid channel. Return exception if error occurs.
esp32_rmt_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
if (self->pin != -1) { // Check if channel has already been deinitialised.
- rmt_driver_uninstall(self->channel_id);
+ esp32_rmt_deactivate(self);
+ rmt_tx_event_callbacks_t callbacks = {
+ .on_trans_done = NULL,
+ };
+ rmt_tx_register_event_callbacks(self->channel, &callbacks, self);
+ rmt_del_encoder(self->encoder);
+ rmt_del_channel(self->channel);
self->pin = -1; // -1 to indicate RMT is unused
+ self->tx_ongoing = 0;
m_free(self->items);
}
+
return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_1(esp32_rmt_deinit_obj, esp32_rmt_deinit);
// Return the source frequency.
-// Currently only the APB clock (80MHz) can be used but it is possible other
+// Currently only the default clock (80MHz) can be used but it is possible other
// clock sources will added in the future.
static mp_obj_t esp32_rmt_source_freq() {
- return mp_obj_new_int(APB_CLK_FREQ);
+ uint32_t clock_freq;
+ check_esp_err(esp_clk_tree_src_get_freq_hz(RMT_CLK_SRC_DEFAULT, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clock_freq));
+ return mp_obj_new_int(clock_freq);
}
static MP_DEFINE_CONST_FUN_OBJ_0(esp32_rmt_source_freq_obj, esp32_rmt_source_freq);
static MP_DEFINE_CONST_STATICMETHOD_OBJ(esp32_rmt_source_obj, MP_ROM_PTR(&esp32_rmt_source_freq_obj));
@@ -216,7 +255,11 @@ static MP_DEFINE_CONST_STATICMETHOD_OBJ(esp32_rmt_source_obj, MP_ROM_PTR(&esp32_
// Return the clock divider.
static mp_obj_t esp32_rmt_clock_div(mp_obj_t self_in) {
esp32_rmt_obj_t *self = MP_OBJ_TO_PTR(self_in);
- return mp_obj_new_int(self->clock_div);
+ if (self->pin == -1) {
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("already deinitialized"));
+ }
+
+ return mp_obj_new_int(self->clock_freq / self->resolution_hz);
}
static MP_DEFINE_CONST_FUN_OBJ_1(esp32_rmt_clock_div_obj, esp32_rmt_clock_div);
@@ -233,29 +276,86 @@ static mp_obj_t esp32_rmt_wait_done(size_t n_args, const mp_obj_t *pos_args, mp_
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
esp32_rmt_obj_t *self = MP_OBJ_TO_PTR(args[0].u_obj);
+ if (self->pin == -1) {
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("already deinitialized"));
+ } else if (!self->enabled) {
+ return mp_const_true;
+ } else if (args[1].u_int == 0 && self->tx_ongoing > 0) {
+ // shortcut to avoid console spamming with timeout msgs by rmt_tx_wait_all_done()
+ return mp_const_false;
+ }
- esp_err_t err = rmt_wait_tx_done(self->channel_id, args[1].u_int / portTICK_PERIOD_MS);
+ esp_err_t err = rmt_tx_wait_all_done(self->channel, args[1].u_int);
return err == ESP_OK ? mp_const_true : mp_const_false;
}
static MP_DEFINE_CONST_FUN_OBJ_KW(esp32_rmt_wait_done_obj, 1, esp32_rmt_wait_done);
+static mp_uint_t esp32_rmt_stream_ioctl(
+ mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
+ if (request != MP_STREAM_POLL) {
+ *errcode = MP_EINVAL;
+ return MP_STREAM_ERROR;
+ }
+ esp32_rmt_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_uint_t ret = 0;
+ if ((arg & MP_STREAM_POLL_WR) && self->tx_ongoing == 0) {
+ ret |= MP_STREAM_POLL_WR;
+ }
+ return ret;
+}
+
+static const mp_stream_p_t esp32_rmt_stream_p = {
+ .ioctl = esp32_rmt_stream_ioctl,
+};
+
+static void esp32_rmt_loop_in(esp32_rmt_obj_t *self, int new_loop_count) {
+ if (self->enabled && self->tx_ongoing > 0 && self->loop_count != 0 && new_loop_count == 0) {
+ // Break ongoing loop
+ esp32_rmt_deactivate(self);
+ }
+ self->loop_count = new_loop_count;
+}
+
static mp_obj_t esp32_rmt_loop(mp_obj_t self_in, mp_obj_t loop) {
esp32_rmt_obj_t *self = MP_OBJ_TO_PTR(self_in);
- self->loop_en = mp_obj_get_int(loop);
- if (!self->loop_en) {
- bool loop_en;
- check_esp_err(rmt_get_tx_loop_mode(self->channel_id, &loop_en));
- if (loop_en) {
- check_esp_err(rmt_set_tx_loop_mode(self->channel_id, false));
- check_esp_err(rmt_set_tx_intr_en(self->channel_id, true));
- }
+ if (self->pin == -1) {
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("already deinitialized"));
}
+
+ bool loop_en = mp_obj_get_int(loop);
+ esp32_rmt_loop_in(self, loop_en ? -1 : 0);
return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_2(esp32_rmt_loop_obj, esp32_rmt_loop);
+static mp_obj_t esp32_rmt_loop_count(mp_obj_t self_in, mp_obj_t loop) {
+ esp32_rmt_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (self->pin == -1) {
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("already deinitialized"));
+ }
+
+ int loop_count = mp_obj_get_int(loop);
+ if (loop_count < -1) {
+ mp_raise_ValueError(MP_ERROR_TEXT("arg must be -1, 0 or positive"));
+ }
+ esp32_rmt_loop_in(self, loop_count);
+ return mp_const_none;
+}
+static MP_DEFINE_CONST_FUN_OBJ_2(esp32_rmt_loop_count_obj, esp32_rmt_loop_count);
+
static mp_obj_t esp32_rmt_write_pulses(size_t n_args, const mp_obj_t *args) {
esp32_rmt_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ if (self->pin == -1) {
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("already deinitialized"));
+ }
+
+ if (self->enabled) {
+ rmt_tx_wait_all_done(self->channel, -1);
+ } else {
+ check_esp_err(rmt_enable(self->channel));
+ self->enabled = true;
+ }
+
mp_obj_t duration_obj = args[1];
mp_obj_t data_obj = n_args > 2 ? args[2] : mp_const_true;
@@ -290,14 +390,12 @@ static mp_obj_t esp32_rmt_write_pulses(size_t n_args, const mp_obj_t *args) {
if (num_pulses == 0) {
mp_raise_ValueError(MP_ERROR_TEXT("No pulses"));
}
- if (self->loop_en && num_pulses > 126) {
- mp_raise_ValueError(MP_ERROR_TEXT("Too many pulses for loop"));
- }
mp_uint_t num_items = (num_pulses / 2) + (num_pulses % 2);
- if (num_items > self->num_items) {
- self->items = (rmt_item32_t *)m_realloc(self->items, num_items * sizeof(rmt_item32_t *));
- self->num_items = num_items;
+
+ if (num_items > self->cap_items) {
+ self->items = (rmt_symbol_word_t *)m_realloc(self->items, num_items * sizeof(rmt_symbol_word_t *));
+ self->cap_items = num_items;
}
for (mp_uint_t item_index = 0, pulse_index = 0; item_index < num_items; item_index++) {
@@ -314,63 +412,62 @@ static mp_obj_t esp32_rmt_write_pulses(size_t n_args, const mp_obj_t *args) {
}
}
- if (self->loop_en) {
- bool loop_en;
- check_esp_err(rmt_get_tx_loop_mode(self->channel_id, &loop_en));
- if (loop_en) {
- check_esp_err(rmt_set_tx_intr_en(self->channel_id, true));
- check_esp_err(rmt_set_tx_loop_mode(self->channel_id, false));
- }
- check_esp_err(rmt_wait_tx_done(self->channel_id, portMAX_DELAY));
- }
-
- #if !CONFIG_IDF_TARGET_ESP32S3
- check_esp_err(rmt_write_items(self->channel_id, self->items, num_items, false));
- #endif
-
- if (self->loop_en) {
- check_esp_err(rmt_set_tx_intr_en(self->channel_id, false));
- check_esp_err(rmt_set_tx_loop_mode(self->channel_id, true));
- }
+ rmt_transmit_config_t tx_config = {
+ .loop_count = self->loop_count,
+ .flags.eot_level = self->idle_level ? 1 : 0,
+ };
- #if CONFIG_IDF_TARGET_ESP32S3
- check_esp_err(rmt_write_items(self->channel_id, self->items, num_items, false));
- #endif
+ rmt_encoder_reset(self->encoder);
+ check_esp_err(rmt_transmit(self->channel, self->encoder, self->items, num_items * sizeof(rmt_symbol_word_t), &tx_config));
+ self->tx_ongoing += 1;
return mp_const_none;
}
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_rmt(size_t n_args, const mp_obj_t *args) {
+ if (n_args > 0) {
+ esp32_rmt_bitstream_enabled = mp_obj_is_true(args[0]);
+ }
+ return esp32_rmt_bitstream_enabled ? mp_const_true : mp_const_false;
+}
+static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_rmt_bitstream_rmt_fun_obj, 0, 1, esp32_rmt_bitstream_rmt);
+static MP_DEFINE_CONST_STATICMETHOD_OBJ(esp32_rmt_bitstream_rmt_obj, MP_ROM_PTR(&esp32_rmt_bitstream_rmt_fun_obj));
+
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;
+ esp32_rmt_bitstream_enabled = false;
} else {
mp_int_t channel_id = mp_obj_get_int(args[0]);
- if (channel_id < 0 || channel_id > RMT_LAST_TX_CHANNEL) {
+ if (channel_id < 0) {
mp_raise_ValueError(MP_ERROR_TEXT("invalid channel"));
}
- esp32_rmt_bitstream_channel_id = channel_id;
+ esp32_rmt_bitstream_enabled = true;
}
}
- if (esp32_rmt_bitstream_channel_id < 0) {
+ if (!esp32_rmt_bitstream_enabled) {
return mp_const_none;
} else {
- return MP_OBJ_NEW_SMALL_INT(esp32_rmt_bitstream_channel_id);
+ return MP_OBJ_NEW_SMALL_INT(1);
}
}
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) },
+ { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&esp32_rmt_active_obj) },
{ MP_ROM_QSTR(MP_QSTR_clock_div), MP_ROM_PTR(&esp32_rmt_clock_div_obj) },
{ 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_loop_count), MP_ROM_PTR(&esp32_rmt_loop_count_obj) },
{ MP_ROM_QSTR(MP_QSTR_write_pulses), MP_ROM_PTR(&esp32_rmt_write_pulses_obj) },
// Static methods
+ { MP_ROM_QSTR(MP_QSTR_bitstream_rmt), MP_ROM_PTR(&esp32_rmt_bitstream_rmt_obj) },
{ MP_ROM_QSTR(MP_QSTR_bitstream_channel), MP_ROM_PTR(&esp32_rmt_bitstream_channel_obj) },
// Class methods
@@ -387,7 +484,8 @@ MP_DEFINE_CONST_OBJ_TYPE(
MP_TYPE_FLAG_NONE,
make_new, esp32_rmt_make_new,
print, esp32_rmt_print,
- locals_dict, &esp32_rmt_locals_dict
+ locals_dict, &esp32_rmt_locals_dict,
+ protocol, &esp32_rmt_stream_p
);
#endif // SOC_RMT_SUPPORTED
diff --git a/ports/esp32/lockfiles/dependencies.lock.esp32 b/ports/esp32/lockfiles/dependencies.lock.esp32
index 71eccf032..4b0b2d972 100644
--- a/ports/esp32/lockfiles/dependencies.lock.esp32
+++ b/ports/esp32/lockfiles/dependencies.lock.esp32
@@ -30,6 +30,6 @@ direct_dependencies:
- espressif/lan867x
- espressif/mdns
- idf
-manifest_hash: 3b18b5bbac91c9fe5098d3759a37c84ed0828546d8cbc92e26e4c1698e689c8a
+manifest_hash: da32add5eb5e196ac97a99eb579025222ec572f5db4038873fbf9d3b9d6ed5a3
target: esp32
version: 2.0.0
diff --git a/ports/esp32/lockfiles/dependencies.lock.esp32c2 b/ports/esp32/lockfiles/dependencies.lock.esp32c2
index 5f46e6156..5c5cea0c9 100644
--- a/ports/esp32/lockfiles/dependencies.lock.esp32c2
+++ b/ports/esp32/lockfiles/dependencies.lock.esp32c2
@@ -16,6 +16,6 @@ dependencies:
direct_dependencies:
- espressif/mdns
- idf
-manifest_hash: 3b18b5bbac91c9fe5098d3759a37c84ed0828546d8cbc92e26e4c1698e689c8a
+manifest_hash: da32add5eb5e196ac97a99eb579025222ec572f5db4038873fbf9d3b9d6ed5a3
target: esp32c2
version: 2.0.0
diff --git a/ports/esp32/lockfiles/dependencies.lock.esp32c3 b/ports/esp32/lockfiles/dependencies.lock.esp32c3
index 5fb11084e..4c4c869c2 100644
--- a/ports/esp32/lockfiles/dependencies.lock.esp32c3
+++ b/ports/esp32/lockfiles/dependencies.lock.esp32c3
@@ -16,6 +16,6 @@ dependencies:
direct_dependencies:
- espressif/mdns
- idf
-manifest_hash: 3b18b5bbac91c9fe5098d3759a37c84ed0828546d8cbc92e26e4c1698e689c8a
+manifest_hash: da32add5eb5e196ac97a99eb579025222ec572f5db4038873fbf9d3b9d6ed5a3
target: esp32c3
version: 2.0.0
diff --git a/ports/esp32/lockfiles/dependencies.lock.esp32c5 b/ports/esp32/lockfiles/dependencies.lock.esp32c5
new file mode 100644
index 000000000..6f24d0134
--- /dev/null
+++ b/ports/esp32/lockfiles/dependencies.lock.esp32c5
@@ -0,0 +1,21 @@
+dependencies:
+ espressif/mdns:
+ component_hash: 46ee81d32fbf850462d8af1e83303389602f6a6a9eddd2a55104cb4c063858ed
+ dependencies:
+ - name: idf
+ require: private
+ version: '>=5.0'
+ source:
+ registry_url: https://components.espressif.com/
+ type: service
+ version: 1.1.0
+ idf:
+ source:
+ type: idf
+ version: 5.5.1
+direct_dependencies:
+- espressif/mdns
+- idf
+manifest_hash: da32add5eb5e196ac97a99eb579025222ec572f5db4038873fbf9d3b9d6ed5a3
+target: esp32c5
+version: 2.0.0
diff --git a/ports/esp32/lockfiles/dependencies.lock.esp32c6 b/ports/esp32/lockfiles/dependencies.lock.esp32c6
index 4debf5548..b7435e107 100644
--- a/ports/esp32/lockfiles/dependencies.lock.esp32c6
+++ b/ports/esp32/lockfiles/dependencies.lock.esp32c6
@@ -16,6 +16,6 @@ dependencies:
direct_dependencies:
- espressif/mdns
- idf
-manifest_hash: 3b18b5bbac91c9fe5098d3759a37c84ed0828546d8cbc92e26e4c1698e689c8a
+manifest_hash: da32add5eb5e196ac97a99eb579025222ec572f5db4038873fbf9d3b9d6ed5a3
target: esp32c6
version: 2.0.0
diff --git a/ports/esp32/lockfiles/dependencies.lock.esp32s2 b/ports/esp32/lockfiles/dependencies.lock.esp32s2
index bb1443947..a13d9fd40 100644
--- a/ports/esp32/lockfiles/dependencies.lock.esp32s2
+++ b/ports/esp32/lockfiles/dependencies.lock.esp32s2
@@ -1,18 +1,4 @@
dependencies:
- espressif/esp_tinyusb:
- component_hash: 96d232ced7afe1976119b62f7fbf1944a2a78b36228ff6f7b9318394ac1153cc
- dependencies:
- - name: idf
- require: private
- version: '>=5.0'
- - name: espressif/tinyusb
- registry_url: https://components.espressif.com
- require: public
- version: '>=0.14.2'
- source:
- registry_url: https://components.espressif.com/
- type: service
- version: 1.7.6~1
espressif/mdns:
component_hash: 46ee81d32fbf850462d8af1e83303389602f6a6a9eddd2a55104cb4c063858ed
dependencies:
@@ -24,27 +10,28 @@ dependencies:
type: service
version: 1.1.0
espressif/tinyusb:
- component_hash: aa65639878f27a44d349044afd9c3fc134a92bd560874fdac1d836019b5c07ca
+ component_hash: ee1c962cff61eb975d508258d509974d58031cc27ff0d6c4117a67a613a49594
dependencies:
- name: idf
- require: private
version: '>=5.0'
source:
- registry_url: https://components.espressif.com
- type: service
+ git: https://github.com/micropython/tinyusb-espressif.git
+ path: .
+ type: git
targets:
- esp32s2
- esp32s3
- esp32p4
- version: 0.18.0~4
+ - esp32h4
+ version: e4c0ec3caab3d9c25374de7047653b9ced8f14ff
idf:
source:
type: idf
version: 5.5.1
direct_dependencies:
-- espressif/esp_tinyusb
- espressif/mdns
+- espressif/tinyusb
- idf
-manifest_hash: 3b18b5bbac91c9fe5098d3759a37c84ed0828546d8cbc92e26e4c1698e689c8a
+manifest_hash: da32add5eb5e196ac97a99eb579025222ec572f5db4038873fbf9d3b9d6ed5a3
target: esp32s2
version: 2.0.0
diff --git a/ports/esp32/lockfiles/dependencies.lock.esp32s3 b/ports/esp32/lockfiles/dependencies.lock.esp32s3
index 38c17f5d6..d5e7045b7 100644
--- a/ports/esp32/lockfiles/dependencies.lock.esp32s3
+++ b/ports/esp32/lockfiles/dependencies.lock.esp32s3
@@ -1,18 +1,4 @@
dependencies:
- espressif/esp_tinyusb:
- component_hash: 96d232ced7afe1976119b62f7fbf1944a2a78b36228ff6f7b9318394ac1153cc
- dependencies:
- - name: idf
- require: private
- version: '>=5.0'
- - name: espressif/tinyusb
- registry_url: https://components.espressif.com
- require: public
- version: '>=0.14.2'
- source:
- registry_url: https://components.espressif.com/
- type: service
- version: 1.7.6~1
espressif/mdns:
component_hash: 46ee81d32fbf850462d8af1e83303389602f6a6a9eddd2a55104cb4c063858ed
dependencies:
@@ -24,27 +10,28 @@ dependencies:
type: service
version: 1.1.0
espressif/tinyusb:
- component_hash: aa65639878f27a44d349044afd9c3fc134a92bd560874fdac1d836019b5c07ca
+ component_hash: ee1c962cff61eb975d508258d509974d58031cc27ff0d6c4117a67a613a49594
dependencies:
- name: idf
- require: private
version: '>=5.0'
source:
- registry_url: https://components.espressif.com
- type: service
+ git: https://github.com/micropython/tinyusb-espressif.git
+ path: .
+ type: git
targets:
- esp32s2
- esp32s3
- esp32p4
- version: 0.18.0~4
+ - esp32h4
+ version: e4c0ec3caab3d9c25374de7047653b9ced8f14ff
idf:
source:
type: idf
version: 5.5.1
direct_dependencies:
-- espressif/esp_tinyusb
- espressif/mdns
+- espressif/tinyusb
- idf
-manifest_hash: 3b18b5bbac91c9fe5098d3759a37c84ed0828546d8cbc92e26e4c1698e689c8a
+manifest_hash: da32add5eb5e196ac97a99eb579025222ec572f5db4038873fbf9d3b9d6ed5a3
target: esp32s3
version: 2.0.0
diff --git a/ports/esp32/machine_adc.c b/ports/esp32/machine_adc.c
index c5575d45e..432df3d3a 100644
--- a/ports/esp32/machine_adc.c
+++ b/ports/esp32/machine_adc.c
@@ -100,6 +100,13 @@ static const machine_adc_obj_t madc_obj[] = {
{{&machine_adc_type}, ADCBLOCK1, ADC_CHANNEL_3, GPIO_NUM_3},
{{&machine_adc_type}, ADCBLOCK1, ADC_CHANNEL_4, GPIO_NUM_4},
{{&machine_adc_type}, ADCBLOCK2, ADC_CHANNEL_0, GPIO_NUM_5},
+ #elif CONFIG_IDF_TARGET_ESP32C5
+ {{&machine_adc_type}, ADCBLOCK1, ADC_CHANNEL_0, GPIO_NUM_1},
+ {{&machine_adc_type}, ADCBLOCK1, ADC_CHANNEL_1, GPIO_NUM_2},
+ {{&machine_adc_type}, ADCBLOCK1, ADC_CHANNEL_2, GPIO_NUM_3},
+ {{&machine_adc_type}, ADCBLOCK1, ADC_CHANNEL_3, GPIO_NUM_4},
+ {{&machine_adc_type}, ADCBLOCK1, ADC_CHANNEL_4, GPIO_NUM_5},
+ {{&machine_adc_type}, ADCBLOCK1, ADC_CHANNEL_5, GPIO_NUM_6},
#elif CONFIG_IDF_TARGET_ESP32C6
{{&machine_adc_type}, ADCBLOCK1, ADC_CHANNEL_0, GPIO_NUM_0},
{{&machine_adc_type}, ADCBLOCK1, ADC_CHANNEL_1, GPIO_NUM_1},
diff --git a/ports/esp32/machine_bitstream.c b/ports/esp32/machine_bitstream.c
index ed7fcc407..60addcc15 100644
--- a/ports/esp32/machine_bitstream.c
+++ b/ports/esp32/machine_bitstream.c
@@ -91,96 +91,95 @@ static void IRAM_ATTR machine_bitstream_high_low_bitbang(mp_hal_pin_obj_t pin, u
}
#if SOC_RMT_SUPPORTED
+
/******************************************************************************/
// RMT implementation
-#include "driver/rmt.h"
-
-// 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 }}};
-
-// 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++;
- }
-
- *translated_size = size;
- *item_num = num;
-}
-
-// Use the reserved RMT channel to stream high/low data on the specified pin.
-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);
+#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 3, 0)
+#include "rmt_private.h"
+#endif
+#include "driver/rmt_tx.h"
+#include "driver/rmt_encoder.h"
+static bool machine_bitstream_high_low_rmt(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len) {
// 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_core1(config.channel));
+ uint32_t clock_div = 2;
+ rmt_channel_handle_t channel = NULL;
+ rmt_tx_channel_config_t tx_chan_config = {
+ .clk_src = RMT_CLK_SRC_DEFAULT,
+ .gpio_num = pin,
+ .mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL,
+ .resolution_hz = APB_CLK_FREQ / clock_div,
+ .trans_queue_depth = 1,
+ };
+ if (rmt_new_tx_channel(&tx_chan_config, &channel) != ESP_OK) {
+ return false;
+ }
+ check_esp_err(rmt_enable(channel));
// Get the tick rate in kHz (this will likely be 40000).
- uint32_t counter_clk_khz = 0;
- check_esp_err(rmt_get_counter_clock(config.channel, &counter_clk_khz));
-
+ uint32_t counter_clk_khz = APB_CLK_FREQ / clock_div;
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));
+ // Example: 500ns = 40000 * 500 / 1e6 = 20 ticks
+ // 20 ticks / 40MHz = 500e-9
+ rmt_bytes_encoder_config_t bytes_encoder_config = {
+ .bit0 = {
+ .level0 = 1,
+ .duration0 = (counter_clk_khz * timing_ns[0]) / 1e6,
+ .level1 = 0,
+ .duration1 = (counter_clk_khz * timing_ns[1]) / 1e6,
+ },
+ .bit1 = {
+ .level0 = 1,
+ .duration0 = (counter_clk_khz * timing_ns[2]) / 1e6,
+ .level1 = 0,
+ .duration1 = (counter_clk_khz * timing_ns[3]) / 1e6,
+ },
+ .flags.msb_first = 1
+ };
+
+ // Install the bits->highlow encoder.
+ rmt_encoder_handle_t encoder;
+ check_esp_err(rmt_new_bytes_encoder(&bytes_encoder_config, &encoder));
+
+ rmt_transmit_config_t tx_config = {
+ .loop_count = 0,
+ .flags.eot_level = 0,
+ };
+
+ // Stream the byte data using the encoder.
+ rmt_encoder_reset(encoder);
+ check_esp_err(rmt_transmit(channel, encoder, buf, len, &tx_config));
+
+ // Wait until completion.
+ rmt_tx_wait_all_done(channel, -1);
+
+ // Disable and release channel.
+ check_esp_err(rmt_del_encoder(encoder));
+ rmt_disable(channel);
+ #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 3, 0)
+ channel->del(channel);
+ #else
+ rmt_del_channel(channel);
+ #endif
// Cancel RMT output to GPIO pin.
esp_rom_gpio_connect_out_signal(pin, SIG_GPIO_OUT_IDX, false, false);
+
+ return true;
}
-#endif
+
+#endif // SOC_RMT_SUPPORTED
+
/******************************************************************************/
// 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 SOC_RMT_SUPPORTED
- if (esp32_rmt_bitstream_channel_id >= 0) {
- machine_bitstream_high_low_rmt(pin, timing_ns, buf, len, esp32_rmt_bitstream_channel_id);
+ if (esp32_rmt_bitstream_enabled && machine_bitstream_high_low_rmt(pin, timing_ns, buf, len)) {
+ // Use of RMT was successful.
return;
}
#endif
diff --git a/ports/esp32/machine_i2c.c b/ports/esp32/machine_i2c.c
index 74679d01d..9fb89660f 100644
--- a/ports/esp32/machine_i2c.c
+++ b/ports/esp32/machine_i2c.c
@@ -35,6 +35,7 @@
#include "driver/i2c_master.h"
#else
#include "driver/i2c.h"
+#include "esp_clk_tree.h"
#include "hal/i2c_ll.h"
#endif
@@ -224,6 +225,8 @@ int machine_hw_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t n, mp_
#if SOC_I2C_SUPPORT_XTAL
#if CONFIG_XTAL_FREQ > 0
#define I2C_SCLK_FREQ (CONFIG_XTAL_FREQ * 1000000)
+#elif CONFIG_XTAL_FREQ == 0 && CONFIG_IDF_TARGET_ESP32C5
+// The crystal is auto-detected, so the I2C sclk frequency will be computed at runtime.
#else
#error "I2C uses XTAL but no configured freq"
#endif // CONFIG_XTAL_FREQ
@@ -257,7 +260,13 @@ static void machine_hw_i2c_init(machine_hw_i2c_obj_t *self, bool first_init) {
.master.clk_speed = self->freq,
};
i2c_param_config(self->port, &conf);
- int timeout = i2c_ll_calculate_timeout_us_to_reg_val(I2C_SCLK_FREQ, self->timeout_us);
+ #if CONFIG_IDF_TARGET_ESP32C5
+ uint32_t i2c_sclk_freq;
+ check_esp_err(esp_clk_tree_src_get_freq_hz(I2C_CLK_SRC_DEFAULT, ESP_CLK_TREE_SRC_FREQ_PRECISION_APPROX, &i2c_sclk_freq));
+ #else
+ uint32_t i2c_sclk_freq = I2C_SCLK_FREQ;
+ #endif
+ int timeout = i2c_ll_calculate_timeout_us_to_reg_val(i2c_sclk_freq, self->timeout_us);
i2c_set_timeout(self->port, (timeout > I2C_LL_MAX_TIMEOUT) ? I2C_LL_MAX_TIMEOUT : timeout);
i2c_driver_install(self->port, I2C_MODE_MASTER, 0, 0, 0);
}
diff --git a/ports/esp32/machine_i2s.c b/ports/esp32/machine_i2s.c
index ba6377a76..27b70f1c8 100644
--- a/ports/esp32/machine_i2s.c
+++ b/ports/esp32/machine_i2s.c
@@ -470,4 +470,4 @@ static void mp_machine_i2s_irq_update(machine_i2s_obj_t *self) {
}
}
-MP_REGISTER_ROOT_POINTER(struct _machine_i2s_obj_t *machine_i2s_obj[I2S_NUM_AUTO]);
+MP_REGISTER_ROOT_POINTER(struct _machine_i2s_obj_t *machine_i2s_obj[SOC_I2S_NUM]);
diff --git a/ports/esp32/machine_pin.c b/ports/esp32/machine_pin.c
index 9999223b5..efe673319 100644
--- a/ports/esp32/machine_pin.c
+++ b/ports/esp32/machine_pin.c
@@ -152,7 +152,7 @@ static mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_
// reset the pin to digital if this is a mode-setting init (grab it back from ADC)
if (args[ARG_mode].u_obj != mp_const_none) {
if (rtc_gpio_is_valid_gpio(index)) {
- #if !(CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6)
+ #if !(CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6)
rtc_gpio_deinit(index);
#endif
}
@@ -163,6 +163,11 @@ static mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_
CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_USB_PAD_ENABLE);
}
#endif
+ #if CONFIG_IDF_TARGET_ESP32C5 && !MICROPY_HW_ESP_USB_SERIAL_JTAG
+ if (index == 13 || index == 14) {
+ CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_USB_PAD_ENABLE);
+ }
+ #endif
#if CONFIG_IDF_TARGET_ESP32C6 && !MICROPY_HW_ESP_USB_SERIAL_JTAG
if (index == 12 || index == 13) {
CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_USB_PAD_ENABLE);
diff --git a/ports/esp32/machine_pin.h b/ports/esp32/machine_pin.h
index 6fe9ef0e7..9e247a736 100644
--- a/ports/esp32/machine_pin.h
+++ b/ports/esp32/machine_pin.h
@@ -111,6 +111,32 @@
#define MICROPY_HW_ENABLE_GPIO20 (1)
#define MICROPY_HW_ENABLE_GPIO21 (1)
+#elif CONFIG_IDF_TARGET_ESP32C5
+
+#define MICROPY_HW_ENABLE_GPIO0 (1)
+#define MICROPY_HW_ENABLE_GPIO1 (1)
+#define MICROPY_HW_ENABLE_GPIO2 (1)
+#define MICROPY_HW_ENABLE_GPIO3 (1)
+#define MICROPY_HW_ENABLE_GPIO4 (1)
+#define MICROPY_HW_ENABLE_GPIO5 (1)
+#define MICROPY_HW_ENABLE_GPIO6 (1)
+#define MICROPY_HW_ENABLE_GPIO7 (1)
+#define MICROPY_HW_ENABLE_GPIO8 (1)
+#define MICROPY_HW_ENABLE_GPIO9 (1)
+#define MICROPY_HW_ENABLE_GPIO10 (1)
+#define MICROPY_HW_ENABLE_GPIO11 (1)
+#define MICROPY_HW_ENABLE_GPIO12 (1)
+#if !MICROPY_HW_ESP_USB_SERIAL_JTAG
+#define MICROPY_HW_ENABLE_GPIO13 (1)
+#define MICROPY_HW_ENABLE_GPIO14 (1)
+#endif
+#define MICROPY_HW_ENABLE_GPIO23 (1)
+#define MICROPY_HW_ENABLE_GPIO24 (1)
+#define MICROPY_HW_ENABLE_GPIO25 (1)
+#define MICROPY_HW_ENABLE_GPIO26 (1)
+#define MICROPY_HW_ENABLE_GPIO27 (1)
+#define MICROPY_HW_ENABLE_GPIO28 (1)
+
#elif CONFIG_IDF_TARGET_ESP32C6
#define MICROPY_HW_ENABLE_GPIO0 (1)
diff --git a/ports/esp32/main.c b/ports/esp32/main.c
index bd5775bc6..41eea29b0 100644
--- a/ports/esp32/main.c
+++ b/ports/esp32/main.c
@@ -107,7 +107,7 @@ void mp_task(void *pvParameter) {
#if MICROPY_HW_ESP_USB_SERIAL_JTAG
usb_serial_jtag_init();
#elif MICROPY_HW_ENABLE_USBDEV
- usb_init();
+ usb_phy_init();
#endif
#if MICROPY_HW_ENABLE_UART_REPL
uart_stdout_init();
@@ -145,6 +145,11 @@ soft_reset:
// run boot-up scripts
pyexec_frozen_module("_boot.py", false);
int ret = pyexec_file_if_exists("boot.py");
+
+ #if MICROPY_HW_ENABLE_USBDEV
+ mp_usbd_init();
+ #endif
+
if (ret & PYEXEC_FORCED_EXIT) {
goto soft_reset_exit;
}
@@ -182,7 +187,9 @@ soft_reset_exit:
// Deinit uart before timers, as esp32 uart
// depends on a timer instance
+ #if MICROPY_PY_MACHINE_UART
machine_uart_deinit_all();
+ #endif
machine_timer_deinit_all();
#if MICROPY_PY_ESP32_PCNT
@@ -193,7 +200,7 @@ soft_reset_exit:
mp_thread_deinit();
#endif
- #if MICROPY_HW_ENABLE_USB_RUNTIME_DEVICE
+ #if MICROPY_HW_ENABLE_USBDEV
mp_usbd_deinit();
#endif
@@ -205,7 +212,9 @@ soft_reset_exit:
mp_hal_stdout_tx_str("MPY: soft reboot\r\n");
// deinitialise peripherals
+ #if MICROPY_PY_MACHINE_PWM
machine_pwm_deinit_all();
+ #endif
// TODO: machine_rmt_deinit_all();
machine_pins_deinit();
#if MICROPY_PY_MACHINE_I2C_TARGET
@@ -219,6 +228,7 @@ soft_reset_exit:
mp_deinit();
fflush(stdout);
+
goto soft_reset;
}
diff --git a/ports/esp32/main/idf_component.yml b/ports/esp32/main/idf_component.yml
index cb14ffde6..77904865b 100644
--- a/ports/esp32/main/idf_component.yml
+++ b/ports/esp32/main/idf_component.yml
@@ -1,10 +1,13 @@
## IDF Component Manager Manifest File
dependencies:
espressif/mdns: "~1.1.0"
- espressif/esp_tinyusb:
+ espressif/tinyusb:
rules:
- if: "target in [esp32s2, esp32s3]"
- version: "~1.7.6"
+ # Temporary workaround for https://github.com/hathach/tinyusb/issues/3154
+ # Can be removed once fix is released in espressif/tinyusb
+ git: https://github.com/micropython/tinyusb-espressif.git
+ version: cherrypick/dwc2_zlp_fix
espressif/lan867x:
version: "~1.0.0"
rules:
diff --git a/ports/esp32/modesp32.h b/ports/esp32/modesp32.h
index 81ab94dc6..60c386565 100644
--- a/ports/esp32/modesp32.h
+++ b/ports/esp32/modesp32.h
@@ -1,6 +1,8 @@
#ifndef MICROPY_INCLUDED_ESP32_MODESP32_H
#define MICROPY_INCLUDED_ESP32_MODESP32_H
+#include "driver/rmt_tx.h"
+
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
#define RTC_VALID_EXT_PINS \
@@ -59,7 +61,7 @@
#define RTC_IS_VALID_EXT_PIN(pin_id) ((1ll << (pin_id)) & RTC_VALID_EXT_PINS)
-extern int8_t esp32_rmt_bitstream_channel_id;
+extern bool esp32_rmt_bitstream_enabled;
extern const mp_obj_type_t esp32_nvs_type;
extern const mp_obj_type_t esp32_partition_type;
@@ -72,6 +74,4 @@ extern const mp_obj_type_t esp32_pcnt_type;
void esp32_pcnt_deinit_all(void);
#endif
-esp_err_t rmt_driver_install_core1(uint8_t channel_id);
-
#endif // MICROPY_INCLUDED_ESP32_MODESP32_H
diff --git a/ports/esp32/modnetwork.h b/ports/esp32/modnetwork.h
index ba69d5cc0..a68db41a3 100644
--- a/ports/esp32/modnetwork.h
+++ b/ports/esp32/modnetwork.h
@@ -26,6 +26,7 @@
#ifndef MICROPY_INCLUDED_ESP32_MODNETWORK_H
#define MICROPY_INCLUDED_ESP32_MODNETWORK_H
+#include "esp_wifi_types.h"
#include "esp_netif.h"
// lan867x component requires newer IDF version
diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h
index 09d75cd1a..7b973ebb9 100644
--- a/ports/esp32/mpconfigport.h
+++ b/ports/esp32/mpconfigport.h
@@ -9,8 +9,6 @@
#include "esp_random.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
-#include "driver/i2s_std.h"
-#include "esp_wifi_types.h"
#ifndef MICROPY_CONFIG_ROM_LEVEL
#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES)
@@ -172,6 +170,8 @@
#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-esp32c2"
#elif CONFIG_IDF_TARGET_ESP32C3
#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-esp32c3"
+#elif CONFIG_IDF_TARGET_ESP32C5
+#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-esp32c5"
#elif CONFIG_IDF_TARGET_ESP32C6
#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-esp32c6"
#endif
@@ -223,19 +223,14 @@
#ifndef MICROPY_HW_USB_VID
#define USB_ESPRESSIF_VID 0x303A
-#if CONFIG_TINYUSB_DESC_USE_ESPRESSIF_VID
#define MICROPY_HW_USB_VID (USB_ESPRESSIF_VID)
-#else
-#define MICROPY_HW_USB_VID (CONFIG_TINYUSB_DESC_CUSTOM_VID)
#endif
#ifndef MICROPY_HW_ENABLE_USB_RUNTIME_DEVICE
#define MICROPY_HW_ENABLE_USB_RUNTIME_DEVICE (1) // Support machine.USBDevice
#endif
-#endif
#ifndef MICROPY_HW_USB_PID
-#if CONFIG_TINYUSB_DESC_USE_DEFAULT_PID
#define _PID_MAP(itf, n) ((CFG_TUD_##itf) << (n))
// A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
// Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
@@ -244,25 +239,16 @@
#define USB_TUSB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
_PID_MAP(MIDI, 3)) // | _PID_MAP(AUDIO, 4) | _PID_MAP(VENDOR, 5) )
#define MICROPY_HW_USB_PID (USB_TUSB_PID)
-#else
-#define MICROPY_HW_USB_PID (CONFIG_TINYUSB_DESC_CUSTOM_PID)
-#endif
#endif
+// These Manufacturer & Product strings are the defaults when using the
+// esp_tinyusb component (which MicroPython used in the past).
#ifndef MICROPY_HW_USB_MANUFACTURER_STRING
-#ifdef CONFIG_TINYUSB_DESC_MANUFACTURER_STRING
-#define MICROPY_HW_USB_MANUFACTURER_STRING CONFIG_TINYUSB_DESC_MANUFACTURER_STRING
-#else
-#define MICROPY_HW_USB_MANUFACTURER_STRING "MicroPython"
-#endif
+#define MICROPY_HW_USB_MANUFACTURER_STRING "Espressif Systems"
#endif
#ifndef MICROPY_HW_USB_PRODUCT_FS_STRING
-#ifdef CONFIG_TINYUSB_DESC_PRODUCT_STRING
-#define MICROPY_HW_USB_PRODUCT_FS_STRING CONFIG_TINYUSB_DESC_PRODUCT_STRING
-#else
-#define MICROPY_HW_USB_PRODUCT_FS_STRING "Board in FS mode"
-#endif
+#define MICROPY_HW_USB_PRODUCT_FS_STRING "Espressif Device"
#endif
#endif // MICROPY_HW_ENABLE_USBDEV
diff --git a/ports/esp32/usb.c b/ports/esp32/usb.c
index 750dd59ee..b90f53aa4 100644
--- a/ports/esp32/usb.c
+++ b/ports/esp32/usb.c
@@ -38,7 +38,7 @@
static usb_phy_handle_t phy_hdl;
-void usb_init(void) {
+void usb_phy_init(void) {
// ref: https://github.com/espressif/esp-usb/blob/4b6a798d0bed444fff48147c8dcdbbd038e92892/device/esp_tinyusb/tinyusb.c
// Configure USB PHY
@@ -51,10 +51,6 @@ void usb_init(void) {
// Init ESP USB Phy
usb_new_phy(&phy_conf, &phy_hdl);
-
- // Init MicroPython / TinyUSB
- mp_usbd_init();
-
}
#if CONFIG_IDF_TARGET_ESP32S3
diff --git a/ports/esp32/usb.h b/ports/esp32/usb.h
index 2bfa3d31a..99437266d 100644
--- a/ports/esp32/usb.h
+++ b/ports/esp32/usb.h
@@ -28,7 +28,7 @@
#define MICROPY_HW_USB_CDC_TX_TIMEOUT_MS (500)
-void usb_init(void);
+void usb_phy_init(void);
void usb_usj_mode(void);
#endif // MICROPY_INCLUDED_ESP32_USB_H
diff --git a/ports/mimxrt/main.c b/ports/mimxrt/main.c
index 22809916e..dcb1ede16 100644
--- a/ports/mimxrt/main.c
+++ b/ports/mimxrt/main.c
@@ -170,8 +170,12 @@ int main(void) {
#if MICROPY_PY_NETWORK
mod_network_deinit();
#endif
+ #if MICROPY_PY_MACHINE_UART
machine_uart_deinit_all();
+ #endif
+ #if MICROPY_PY_MACHINE_PWM
machine_pwm_deinit_all();
+ #endif
soft_timer_deinit();
gc_sweep_all();
mp_deinit();
diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt
index 120d07bcc..c4a081e2e 100644
--- a/ports/rp2/CMakeLists.txt
+++ b/ports/rp2/CMakeLists.txt
@@ -644,12 +644,6 @@ separate_arguments(MICROPY_CPP_FLAGS_EXTRA)
# Include the main MicroPython cmake rules.
include(${MICROPY_DIR}/py/mkrules.cmake)
-set(GEN_PINS_AF_CSV "${MICROPY_PORT_DIR}/boards/rp2_af.csv")
-set(GEN_PINS_PREFIX "${MICROPY_PORT_DIR}/boards/rp2_prefix.c")
-set(GEN_PINS_MKPINS "${MICROPY_PORT_DIR}/boards/make-pins.py")
-set(GEN_PINS_SRC "${CMAKE_BINARY_DIR}/pins_${MICROPY_BOARD}.c")
-set(GEN_PINS_HDR "${MICROPY_GENHDR_DIR}/pins.h")
-
if(NOT PICO_NUM_GPIOS)
set(PICO_NUM_GPIOS 30)
endif()
@@ -658,6 +652,21 @@ if(NOT PICO_NUM_EXT_GPIOS)
set(PICO_NUM_EXT_GPIOS 10)
endif()
+if(PICO_RP2040)
+ set(GEN_PINS_AF_CSV "${MICROPY_PORT_DIR}/boards/rp2040_af.csv")
+elseif(PICO_RP2350)
+ if(PICO_NUM_GPIOS EQUAL 48)
+ set(GEN_PINS_AF_CSV "${MICROPY_PORT_DIR}/boards/rp2350b_af.csv")
+ else()
+ set(GEN_PINS_AF_CSV "${MICROPY_PORT_DIR}/boards/rp2350_af.csv")
+ endif()
+endif()
+
+set(GEN_PINS_PREFIX "${MICROPY_PORT_DIR}/boards/rp2_prefix.c")
+set(GEN_PINS_MKPINS "${MICROPY_PORT_DIR}/boards/make-pins.py")
+set(GEN_PINS_SRC "${CMAKE_BINARY_DIR}/pins_${MICROPY_BOARD}.c")
+set(GEN_PINS_HDR "${MICROPY_GENHDR_DIR}/pins.h")
+
if(NOT MICROPY_BOARD_PINS)
set(MICROPY_BOARD_PINS "${MICROPY_BOARD_DIR}/pins.csv")
endif()
diff --git a/ports/rp2/boards/make-pins.py b/ports/rp2/boards/make-pins.py
index 1da2edb7c..07ce052bb 100755
--- a/ports/rp2/boards/make-pins.py
+++ b/ports/rp2/boards/make-pins.py
@@ -60,6 +60,15 @@ class Rp2Pin(boardgen.Pin):
m = re.match("([A-Z][A-Z0-9][A-Z]+)(([0-9]+)(_.*)?)?", af)
af_fn = m.group(1)
af_unit = int(m.group(3)) if m.group(3) is not None else 0
+ if af_idx == 10:
+ # AF11 uses UART_AUX in lieu of UART
+ af_fn = "UART_AUX"
+ if af_fn.startswith("QMI"):
+ # The full func name is GPIO_FUNC_XIP_CS1
+ af_fn = "XIP_CS1"
+ if af_fn.startswith("TRACE"):
+ # The various TRACE functions all belong under CORESIGHT_TRACE
+ af_fn = "CORESIGHT_TRACE"
if af_fn == "PIO":
# Pins can be either PIO unit (unlike, say, I2C where a
# pin can only be I2C0 _or_ I2C1, both sharing the same AF
diff --git a/ports/rp2/boards/rp2_af.csv b/ports/rp2/boards/rp2040_af.csv
index 454f7ed2d..454f7ed2d 100644
--- a/ports/rp2/boards/rp2_af.csv
+++ b/ports/rp2/boards/rp2040_af.csv
diff --git a/ports/rp2/boards/rp2350_af.csv b/ports/rp2/boards/rp2350_af.csv
new file mode 100644
index 000000000..cca30d9e7
--- /dev/null
+++ b/ports/rp2/boards/rp2350_af.csv
@@ -0,0 +1,31 @@
+Pin,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11
+GPIO0,SPI0_RX,UART0_TX,I2C0_SDA,PWM0_A,SIO,PIO0,PIO1,PIO2,QMI_CS1,USB_OVCUR_DET,
+GPIO1,SPI0_CS,UART0_RX,I2C0_SCL,PWM0_B,SIO,PIO0,PIO1,PIO2,TRACECLK,USB_VBUS_DET,
+GPIO2,SPI0_SCK,UART0_CTS,I2C1_SDA,PWM1_A,SIO,PIO0,PIO1,PIO2,TRACEDATA0,USB_VBUS_EN,UART0_TX
+GPIO3,SPI0_TX,UART0_RTS,I2C1_SCL,PWM1_B,SIO,PIO0,PIO1,PIO2,TRACEDATA1,USB_OVCUR_DET,UART0_RX
+GPIO4,SPI0_RX,UART1_TX,I2C0_SDA,PWM2_A,SIO,PIO0,PIO1,PIO2,TRACEDATA2,USB_VBUS_DET,
+GPIO5,SPI0_CS,UART1_RX,I2C0_SCL,PWM2_B,SIO,PIO0,PIO1,PIO2,TRACEDATA3,USB_VBUS_EN,
+GPIO6,SPI0_SCK,UART1_CTS,I2C1_SDA,PWM3_A,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,UART1_TX
+GPIO7,SPI0_TX,UART1_RTS,I2C1_SCL,PWM3_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET,UART1_RX
+GPIO8,SPI1_RX,UART1_TX,I2C0_SDA,PWM4_A,SIO,PIO0,PIO1,PIO2,QMI_CS1,USB_VBUS_EN,
+GPIO9,SPI1_CS,UART1_RX,I2C0_SCL,PWM4_B,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,
+GPIO10,SPI1_SCK,UART1_CTS,I2C1_SDA,PWM5_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET,UART1_TX
+GPIO11,SPI1_TX,UART1_RTS,I2C1_SCL,PWM5_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN,UART1_RX
+GPIO12,SPI1_RX,UART0_TX,I2C0_SDA,PWM6_A,SIO,PIO0,PIO1,PIO2,GPCK_GPIN0,USB_OVCUR_DET,
+GPIO13,SPI1_CS,UART0_RX,I2C0_SCL,PWM6_B,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT0,USB_VBUS_DET,
+GPIO14,SPI1_SCK,UART0_CTS,I2C1_SDA,PWM7_A,SIO,PIO0,PIO1,PIO2,GPCK_GPIN1,USB_VBUS_EN,UART0_TX
+GPIO15,SPI1_TX,UART0_RTS,I2C1_SCL,PWM7_B,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT1,USB_OVCUR_DET,UART0_RX
+GPIO16,SPI0_RX,UART0_TX,I2C0_SDA,PWM0_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET,
+GPIO17,SPI0_CS,UART0_RX,I2C0_SCL,PWM0_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN,
+GPIO18,SPI0_SCK,UART0_CTS,I2C1_SDA,PWM1_A,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,UART0_TX
+GPIO19,SPI0_TX,UART0_RTS,I2C1_SCL,PWM1_B,SIO,PIO0,PIO1,PIO2,QMI_CS1,USB_VBUS_DET,UART0_RX
+GPIO20,SPI0_RX,UART1_TX,I2C0_SDA,PWM2_A,SIO,PIO0,PIO1,PIO2,GPCK_GPIN0,USB_VBUS_EN,
+GPIO21,SPI0_CS,UART1_RX,I2C0_SCL,PWM2_B,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT0,USB_OVCUR_DET,
+GPIO22,SPI0_SCK,UART1_CTS,I2C1_SDA,PWM3_A,SIO,PIO0,PIO1,PIO2,GPCK_GPIN1,USB_VBUS_DET,UART1_TX
+GPIO23,SPI0_TX,UART1_RTS,I2C1_SCL,PWM3_B,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT1,USB_VBUS_EN,UART1_RX
+GPIO24,SPI1_RX,UART1_TX,I2C0_SDA,PWM4_A,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT2,USB_OVCUR_DET,
+GPIO25,SPI1_CS,UART1_RX,I2C0_SCL,PWM4_B,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT3,USB_VBUS_DET,
+GPIO26,SPI1_SCK,UART1_CTS,I2C1_SDA,PWM5_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN,UART1_TX
+GPIO27,SPI1_TX,UART1_RTS,I2C1_SCL,PWM5_B,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,UART1_RX
+GPIO28,SPI1_RX,UART0_TX,I2C0_SDA,PWM6_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET,
+GPIO29,SPI1_CS,UART0_RX,I2C0_SCL,PWM6_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN,
diff --git a/ports/rp2/boards/rp2350b_af.csv b/ports/rp2/boards/rp2350b_af.csv
new file mode 100644
index 000000000..3b9053f58
--- /dev/null
+++ b/ports/rp2/boards/rp2350b_af.csv
@@ -0,0 +1,49 @@
+Pin,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11
+GPIO0,SPI0_RX,UART0_TX,I2C0_SDA,PWM0_A,SIO,PIO0,PIO1,PIO2,QMI_CS1,USB_OVCUR_DET,
+GPIO1,SPI0_CS,UART0_RX,I2C0_SCL,PWM0_B,SIO,PIO0,PIO1,PIO2,TRACECLK,USB_VBUS_DET,
+GPIO2,SPI0_SCK,UART0_CTS,I2C1_SDA,PWM1_A,SIO,PIO0,PIO1,PIO2,TRACEDATA0,USB_VBUS_EN,UART0_TX
+GPIO3,SPI0_TX,UART0_RTS,I2C1_SCL,PWM1_B,SIO,PIO0,PIO1,PIO2,TRACEDATA1,USB_OVCUR_DET,UART0_RX
+GPIO4,SPI0_RX,UART1_TX,I2C0_SDA,PWM2_A,SIO,PIO0,PIO1,PIO2,TRACEDATA2,USB_VBUS_DET,
+GPIO5,SPI0_CS,UART1_RX,I2C0_SCL,PWM2_B,SIO,PIO0,PIO1,PIO2,TRACEDATA3,USB_VBUS_EN,
+GPIO6,SPI0_SCK,UART1_CTS,I2C1_SDA,PWM3_A,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,UART1_TX
+GPIO7,SPI0_TX,UART1_RTS,I2C1_SCL,PWM3_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET,UART1_RX
+GPIO8,SPI1_RX,UART1_TX,I2C0_SDA,PWM4_A,SIO,PIO0,PIO1,PIO2,QMI_CS1,USB_VBUS_EN,
+GPIO9,SPI1_CS,UART1_RX,I2C0_SCL,PWM4_B,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,
+GPIO10,SPI1_SCK,UART1_CTS,I2C1_SDA,PWM5_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET,UART1_TX
+GPIO11,SPI1_TX,UART1_RTS,I2C1_SCL,PWM5_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN,UART1_RX
+GPIO12,SPI1_RX,UART0_TX,I2C0_SDA,PWM6_A,SIO,PIO0,PIO1,PIO2,GPCK_GPIN0,USB_OVCUR_DET,
+GPIO13,SPI1_CS,UART0_RX,I2C0_SCL,PWM6_B,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT0,USB_VBUS_DET,
+GPIO14,SPI1_SCK,UART0_CTS,I2C1_SDA,PWM7_A,SIO,PIO0,PIO1,PIO2,GPCK_GPIN1,USB_VBUS_EN,UART0_TX
+GPIO15,SPI1_TX,UART0_RTS,I2C1_SCL,PWM7_B,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT1,USB_OVCUR_DET,UART0_RX
+GPIO16,SPI0_RX,UART0_TX,I2C0_SDA,PWM0_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET,
+GPIO17,SPI0_CS,UART0_RX,I2C0_SCL,PWM0_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN,
+GPIO18,SPI0_SCK,UART0_CTS,I2C1_SDA,PWM1_A,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,UART0_TX
+GPIO19,SPI0_TX,UART0_RTS,I2C1_SCL,PWM1_B,SIO,PIO0,PIO1,PIO2,QMI_CS1,USB_VBUS_DET,UART0_RX
+GPIO20,SPI0_RX,UART1_TX,I2C0_SDA,PWM2_A,SIO,PIO0,PIO1,PIO2,GPCK_GPIN0,USB_VBUS_EN,
+GPIO21,SPI0_CS,UART1_RX,I2C0_SCL,PWM2_B,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT0,USB_OVCUR_DET,
+GPIO22,SPI0_SCK,UART1_CTS,I2C1_SDA,PWM3_A,SIO,PIO0,PIO1,PIO2,GPCK_GPIN1,USB_VBUS_DET,UART1_TX
+GPIO23,SPI0_TX,UART1_RTS,I2C1_SCL,PWM3_B,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT1,USB_VBUS_EN,UART1_RX
+GPIO24,SPI1_RX,UART1_TX,I2C0_SDA,PWM4_A,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT2,USB_OVCUR_DET,
+GPIO25,SPI1_CS,UART1_RX,I2C0_SCL,PWM4_B,SIO,PIO0,PIO1,PIO2,GPCK_GPOUT3,USB_VBUS_DET,
+GPIO26,SPI1_SCK,UART1_CTS,I2C1_SDA,PWM5_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN,UART1_TX
+GPIO27,SPI1_TX,UART1_RTS,I2C1_SCL,PWM5_B,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,UART1_RX
+GPIO28,SPI1_RX,UART0_TX,I2C0_SDA,PWM6_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET,
+GPIO29,SPI1_CS,UART0_RX,I2C0_SCL,PWM6_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN,
+GPIO30,SPI1_SCK,UART0_CTS,I2C1_SDA,PWM7_A,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,UART0_TX
+GPIO31,SPI1_TX,UART0_RTS,I2C1_SCL,PWM7_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET,UART0_RX
+GPIO32,SPI0_RX,UART0_TX,I2C0_SDA,PWM8_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN,
+GPIO33,SPI0_CS,UART0_RX,I2C0_SCL,PWM8_B,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,
+GPIO34,SPI0_SCK,UART0_CTS,I2C1_SDA,PWM9_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET,UART0_TX
+GPIO35,SPI0_TX,UART0_RTS,I2C1_SCL,PWM9_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN,UART0_RX
+GPIO36,SPI0_RX,UART1_TX,I2C0_SDA,PWM10_A,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,
+GPIO37,SPI0_CS,UART1_RX,I2C0_SCL,PWM10_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET,
+GPIO38,SPI0_SCK,UART1_CTS,I2C1_SCL,PWM11_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN,UART1_TX
+GPIO39,SPI0_TX,UART1_RTS,I2C1_SCL,PWM11_B,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,UART1_RX
+GPIO40,SPI1_RX,UART1_TX,I2C0_SDA,PWM8_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET,
+GPIO41,SPI1_CS,UART1_RX,I2C0_SCL,PWM8_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN,
+GPIO42,SPI1_SCK,UART1_CTS,I2C1_SDA,PWM9_A,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,UART1_TX
+GPIO43,SPI1_TX,UART1_RTS,I2C1_SCL,PWM9_B,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET,UART1_RX
+GPIO44,SPI1_RX,UART0_TX,I2C0_SDA,PWM10_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_EN,
+GPIO45,SPI1_CS,UART0_RX,I2C0_SCL,PWM10_B,SIO,PIO0,PIO1,PIO2,,USB_OVCUR_DET,
+GPIO46,SPI1_SCK,UART0_CTS,I2C1_SDA,PWM11_A,SIO,PIO0,PIO1,PIO2,,USB_VBUS_DET,UART0_TX
+GPIO47,SPI1_TX,UART0_RTS,I2C1_SCL,PWM11_B,SIO,PIO0,PIO1,PIO2,QMI_CS1,USB_VBUS_EN,UART0_RX
diff --git a/ports/rp2/machine_pin.c b/ports/rp2/machine_pin.c
index 7a2de0c0b..e1a184f32 100644
--- a/ports/rp2/machine_pin.c
+++ b/ports/rp2/machine_pin.c
@@ -515,8 +515,16 @@ static const mp_rom_map_elem_t machine_pin_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_ALT_SIO), MP_ROM_INT(GPIO_FUNC_SIO) },
{ MP_ROM_QSTR(MP_QSTR_ALT_PIO0), MP_ROM_INT(GPIO_FUNC_PIO0) },
{ MP_ROM_QSTR(MP_QSTR_ALT_PIO1), MP_ROM_INT(GPIO_FUNC_PIO1) },
+ #if NUM_PIOS >= 3
+ { MP_ROM_QSTR(MP_QSTR_ALT_PIO2), MP_ROM_INT(GPIO_FUNC_PIO2) },
+ #endif
{ MP_ROM_QSTR(MP_QSTR_ALT_GPCK), MP_ROM_INT(GPIO_FUNC_GPCK) },
{ MP_ROM_QSTR(MP_QSTR_ALT_USB), MP_ROM_INT(GPIO_FUNC_USB) },
+ #if PICO_RP2350
+ { MP_ROM_QSTR(MP_QSTR_ALT_XIP_CS1), MP_ROM_INT(GPIO_FUNC_XIP_CS1) },
+ { MP_ROM_QSTR(MP_QSTR_ALT_CORESIGHT_TRACE), MP_ROM_INT(GPIO_FUNC_CORESIGHT_TRACE) },
+ { MP_ROM_QSTR(MP_QSTR_ALT_UART_AUX), MP_ROM_INT(GPIO_FUNC_UART_AUX) },
+ #endif
};
static MP_DEFINE_CONST_DICT(machine_pin_locals_dict, machine_pin_locals_dict_table);
diff --git a/ports/rp2/main.c b/ports/rp2/main.c
index 1ffcabdfa..f01522f24 100644
--- a/ports/rp2/main.c
+++ b/ports/rp2/main.c
@@ -249,15 +249,21 @@ int main(int argc, char **argv) {
#if MICROPY_PY_NETWORK
mod_network_deinit();
#endif
+ #if MICROPY_PY_MACHINE_I2S
machine_i2s_deinit_all();
+ #endif
rp2_dma_deinit();
rp2_pio_deinit();
#if MICROPY_PY_BLUETOOTH
mp_bluetooth_deinit();
#endif
+ #if MICROPY_PY_MACHINE_PWM
machine_pwm_deinit_all();
+ #endif
machine_pin_deinit();
+ #if MICROPY_PY_MACHINE_UART
machine_uart_deinit_all();
+ #endif
#if MICROPY_PY_MACHINE_I2C_TARGET
mp_machine_i2c_target_deinit_all();
#endif
diff --git a/ports/rp2/pendsv.c b/ports/rp2/pendsv.c
index 05b521fde..a3a855b8d 100644
--- a/ports/rp2/pendsv.c
+++ b/ports/rp2/pendsv.c
@@ -180,5 +180,7 @@ void PendSV_Handler(void) {
#if MICROPY_PY_THREAD
mp_thread_recursive_mutex_unlock(&pendsv_mutex);
+ // Check if a dispatch occurred while the interrupt was being serviced
+ pendsv_resume_run_dispatch();
#endif
}
diff --git a/ports/stm32/boards/NUCLEO_N657X0/mpconfigboard.h b/ports/stm32/boards/NUCLEO_N657X0/mpconfigboard.h
index ccc3fa051..90ea1eae3 100644
--- a/ports/stm32/boards/NUCLEO_N657X0/mpconfigboard.h
+++ b/ports/stm32/boards/NUCLEO_N657X0/mpconfigboard.h
@@ -74,6 +74,17 @@
#define MICROPY_HW_USB_HS_IN_FS (1)
#define MICROPY_HW_USB_MAIN_DEV (USB_PHY_HS_ID)
+// Ethernet via RMII
+#define MICROPY_HW_ETH_MDC (pin_G11)
+#define MICROPY_HW_ETH_MDIO (pin_F4)
+#define MICROPY_HW_ETH_RMII_REF_CLK (pin_F7)
+#define MICROPY_HW_ETH_RMII_CRS_DV (pin_F10)
+#define MICROPY_HW_ETH_RMII_RXD0 (pin_F14)
+#define MICROPY_HW_ETH_RMII_RXD1 (pin_F15)
+#define MICROPY_HW_ETH_RMII_TX_EN (pin_F11)
+#define MICROPY_HW_ETH_RMII_TXD0 (pin_F12)
+#define MICROPY_HW_ETH_RMII_TXD1 (pin_F13)
+
/******************************************************************************/
// Bootloader configuration
diff --git a/ports/stm32/boards/NUCLEO_N657X0/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_N657X0/mpconfigboard.mk
index fa64cb170..777f22e61 100644
--- a/ports/stm32/boards/NUCLEO_N657X0/mpconfigboard.mk
+++ b/ports/stm32/boards/NUCLEO_N657X0/mpconfigboard.mk
@@ -24,3 +24,6 @@ endif
# MicroPython settings
MICROPY_FLOAT_IMPL = double
+MICROPY_PY_LWIP = 1
+MICROPY_PY_SSL = 1
+MICROPY_SSL_MBEDTLS = 1
diff --git a/ports/stm32/boards/NUCLEO_N657X0/pins.csv b/ports/stm32/boards/NUCLEO_N657X0/pins.csv
index 033f0a552..a8a3f6c5a 100644
--- a/ports/stm32/boards/NUCLEO_N657X0/pins.csv
+++ b/ports/stm32/boards/NUCLEO_N657X0/pins.csv
@@ -44,6 +44,17 @@ A5,PG15
-SPI5_MISO,PG1
-SPI5_MOSI,PG2
+# ETH1 RMII
+,PG11
+,PF4
+,PF7
+,PF10
+,PF11
+,PF12
+,PF13
+,PF14
+,PF15
+
-BUTTON,PC13
LED_BLUE,PG8
LED_RED,PG10
diff --git a/ports/stm32/boards/OPENMV_N6/mpconfigboard.h b/ports/stm32/boards/OPENMV_N6/mpconfigboard.h
index 6e6bb4357..0d63ff224 100644
--- a/ports/stm32/boards/OPENMV_N6/mpconfigboard.h
+++ b/ports/stm32/boards/OPENMV_N6/mpconfigboard.h
@@ -126,6 +126,24 @@
#define MICROPY_HW_USB_PID_CDC_HID (MICROPY_HW_USB_PID)
#define MICROPY_HW_USB_PID_CDC_MSC_HID (MICROPY_HW_USB_PID)
+// Ethernet via RGMII
+#define NETWORK_LAN_PHY (ETH_PHY_RTL8211)
+#define MICROPY_HW_ETH_MDC (pin_D1)
+#define MICROPY_HW_ETH_MDIO (pin_D12)
+#define MICROPY_HW_ETH_RGMII_CLK125 (pin_F2)
+#define MICROPY_HW_ETH_RGMII_GTX_CLK (pin_F0)
+#define MICROPY_HW_ETH_RGMII_TXD0 (pin_F12)
+#define MICROPY_HW_ETH_RGMII_TXD1 (pin_F13)
+#define MICROPY_HW_ETH_RGMII_TXD2 (pin_G3)
+#define MICROPY_HW_ETH_RGMII_TXD3 (pin_G4)
+#define MICROPY_HW_ETH_RGMII_TX_CTL (pin_F11)
+#define MICROPY_HW_ETH_RGMII_RX_CLK (pin_F7)
+#define MICROPY_HW_ETH_RGMII_RXD0 (pin_F14)
+#define MICROPY_HW_ETH_RGMII_RXD1 (pin_F15)
+#define MICROPY_HW_ETH_RGMII_RXD2 (pin_F8)
+#define MICROPY_HW_ETH_RGMII_RXD3 (pin_F9)
+#define MICROPY_HW_ETH_RGMII_RX_CTL (pin_F10)
+
// Murata 1YN configuration
#define CYW43_CHIPSET_FIRMWARE_INCLUDE_FILE "lib/cyw43-driver/firmware/w43439_sdio_1yn_7_95_59_combined.h"
#define CYW43_WIFI_NVRAM_INCLUDE_FILE "lib/cyw43-driver/firmware/wifi_nvram_1yn.h"
diff --git a/ports/stm32/boards/OPENMV_N6/pins.csv b/ports/stm32/boards/OPENMV_N6/pins.csv
index 52f6c9249..2ca075a15 100644
--- a/ports/stm32/boards/OPENMV_N6/pins.csv
+++ b/ports/stm32/boards/OPENMV_N6/pins.csv
@@ -95,7 +95,20 @@ P16,PE12
I2C4_SCL,PE13
I2C4_SDA,PE14
,PE15
+,PF0
+,PF2
+,PF7
+,PF8
+,PF9
+,PF10
+,PF11
+,PF12
+,PF13
+,PF14
+,PF15
P6,PG0
+,PG3
+,PG4
P9,PG12
P7,PG13
BAT_ADC,PG15
diff --git a/ports/stm32/boards/stm32n657_af.csv b/ports/stm32/boards/stm32n657_af.csv
index 220d27b3f..c02c658bd 100644
--- a/ports/stm32/boards/stm32n657_af.csv
+++ b/ports/stm32/boards/stm32n657_af.csv
@@ -20,6 +20,7 @@ PortC,PC9 , , , ,
PortC,PC10, , , , , , , , , , ,SDMMC1_D2 , , , , , ,
PortC,PC11, , , , , , , , , , ,SDMMC1_D3 , , , , , ,
PortC,PC12, , , , , , , , , , ,SDMMC1_CK , , , , , ,
+PortD,PD1 , , , , , , , , , , , ,ETH1_MDC , , , , ,
PortD,PD2 , , , , , , , , , , , ,SDMMC2_CK , , , , ,
PortD,PD5 , , , , , , , ,USART2_TX , , , , , , , , ,
PortD,PD6 , , , , ,TIM15_CH2 , , , , , , , , , , , ,
@@ -27,6 +28,7 @@ PortD,PD7 , , , ,
PortD,PD8 , , , , , , , ,USART3_TX , , , , , , , , ,
PortD,PD9 , , , , , , , ,USART3_RX , , , , , , , , ,
PortD,PD11, , , , , ,SPI2_MISO , , , , , , , , , , ,
+PortD,PD12, , , , , , , , , , , ,ETH1_MDIO , , , , ,
PortD,PD13, , ,TIM4_CH2 , , , , , , , , , , , , , ,
PortE,PE5 , , , , , , , ,USART1_TX , , , , , , , , ,
PortE,PE6 , , , , , , , ,USART1_RX , , , , , , , , ,
@@ -37,13 +39,28 @@ PortE,PE12, , , ,
PortE,PE13, , , , ,I2C4_SCL , , , , , , , , , , , ,
PortE,PE14, , , , ,I2C4_SDA , , , , , , , , , , , ,
PortE,PE15, , , , , ,SPI5_SCK , , , , , , , , , , ,
+PortF,PF0 , , , , , , , , , , , , ,ETH1_RGMII_GTX_CLK , , , ,
+PortF,PF2 , , , , , , , , , , , ,ETH1_RGMII_CLK125 , , , , ,
PortF,PF3 , , , , , , , ,USART2_RTS , , , , , , , , ,ADC1_INP16
+PortF,PF4 , , , , , , , , , , , ,ETH1_MDIO , , , , ,
PortF,PF6 , , , , , , , ,USART2_RX , , , , , , , , ,
+PortF,PF7 , , , , , , , , , , , ,ETH1_RMII_REF_CLK/ETH1_RGMII_RX_CLK , , , , ,
+PortF,PF8 , , , , , , , , , , , ,ETH1_RGMII_RXD2 , , , , ,
+PortF,PF9 , , , , , , , , , , , ,ETH1_RGMII_RXD3 , , , , ,
+PortF,PF10, , , , , , , , , , , ,ETH1_RMII_CRS_DV/ETH1_RGMII_RX_CTL , , , , ,
+PortF,PF11, , , , , , , , , , , ,ETH1_RMII_TX_EN/ETH1_RGMII_TX_CTL , , , , ,
+PortF,PF12, , , , , , , , , , , ,ETH1_RMII_TXD0/ETH1_RGMII_TXD0 , , , , ,
+PortF,PF13, , , , , , , , , , , ,ETH1_RMII_TXD1/ETH1_RGMII_TXD1 , , , , ,
+PortF,PF14, , , , , , , , , , , ,ETH1_RMII_RXD0/ETH1_RGMII_RXD0 , , , , ,
+PortF,PF15, , , , , , , , , , , ,ETH1_RMII_RXD1/ETH1_RGMII_RXD1 , , , , ,
PortG,PG0 , , ,TIM12_CH1 , , , , , , , , , , , , , ,
PortG,PG1 , , , , , ,SPI5_MISO , , , , , , , , , , ,
PortG,PG2 , , , , , ,SPI5_MOSI , , , , , , , , , , ,
+PortG,PG3 , , , , , , , , , , , ,ETH1_RGMII_TXD2 , , , , ,
+PortG,PG4 , , , , , , , , , , , ,ETH1_RGMII_TXD3 , , , , ,
PortG,PG5 , , , , , , , ,USART2_CTS , , , , , , , , ,
PortG,PG8 , , , , , , , , , , , ,SDMMC2_D1 , , , , ,
+PortG,PG11, , , , , , , , , , , ,ETH1_MDC , , , , ,
PortG,PG12, ,TIM17_CH1 , , , , , , , , , , , , , , ,
PortG,PG13, , ,TIM4_CH1 , , , , ,USART3_RTS , , , , , , , , ,
PortG,PG15, , , , , , , , , , , , , , , , ,ADC12_INP7/ADC12_INN3
diff --git a/ports/stm32/boards/stm32n6xx_hal_conf_base.h b/ports/stm32/boards/stm32n6xx_hal_conf_base.h
index 641a003d8..87556cf15 100644
--- a/ports/stm32/boards/stm32n6xx_hal_conf_base.h
+++ b/ports/stm32/boards/stm32n6xx_hal_conf_base.h
@@ -160,7 +160,6 @@
#include "stm32n6xx_hal_dcmipp.h"
#include "stm32n6xx_hal_dma2d.h"
#include "stm32n6xx_hal_dts.h"
-#include "stm32n6xx_hal_eth.h"
#include "stm32n6xx_hal_exti.h"
#include "stm32n6xx_hal_fdcan.h"
#include "stm32n6xx_hal_gfxmmu.h"
diff --git a/ports/stm32/eth.c b/ports/stm32/eth.c
index 9f6553068..60f2a23de 100644
--- a/ports/stm32/eth.c
+++ b/ports/stm32/eth.c
@@ -41,8 +41,19 @@
#include "lwip/dhcp.h"
#include "netif/ethernet.h"
+// Register and IRQ compatibility for STM32N6.
+#if defined(STM32N6)
+#define ETH ETH1
+#define ETH_MACMDIOAR_MB (ETH_MACMDIOAR_GB)
+#define ETH_MACMDIOAR_MOC_Msk (ETH_MACMDIOAR_GOC_Msk)
+#define ETH_MACMDIOAR_MOC_WR (ETH_MACMDIOAR_GOC_0)
+#define ETH_MACMDIOAR_MOC_RD (ETH_MACMDIOAR_GOC_1 | ETH_MACMDIOAR_GOC_0)
+#define ETH_IRQn ETH1_IRQn
+#define ETH_IRQHandler ETH1_IRQHandler
+#endif
+
// ETH DMA RX and TX descriptor definitions
-#if defined(STM32H5)
+#if defined(STM32H5) || defined(STM32N6)
#define RX_DESCR_3_OWN_Pos (31)
#define RX_DESCR_3_IOC_Pos (30)
#define RX_DESCR_3_BUF1V_Pos (24)
@@ -52,6 +63,7 @@
#define TX_DESCR_3_FD_Pos (29)
#define TX_DESCR_3_LD_Pos (28)
#define TX_DESCR_3_CIC_Pos (16)
+#define TX_DESCR_2_IOC_Pos (31)
#define TX_DESCR_2_B1L_Pos (0)
#define TX_DESCR_2_B1L_Msk (0x3fff << TX_DESCR_2_B1L_Pos)
#elif defined(STM32H7)
@@ -85,15 +97,38 @@
#define TX_DESCR_1_TBS1_Pos (0)
#endif
+// Static alternate function macro.
+#if defined(STM32N6)
+#define STATIC_AF_ETH(signal) STATIC_AF_ETH1_##signal
+#else
+#define STATIC_AF_ETH(signal) STATIC_AF_ETH_##signal
+#endif
+
// Configuration values
#define PHY_INIT_TIMEOUT_MS (10000)
-#define RX_BUF_SIZE (1524) // includes 4-byte CRC at end
-#define TX_BUF_SIZE (1524)
+// These buffer sizes need to be a multiple of 8 (for STM32N6 at least).
+#define RX_BUF_SIZE (1528) // includes 4-byte CRC at end
+#define TX_BUF_SIZE (1528)
+#if defined(MICROPY_HW_ETH_RMII_REF_CLK)
+// RMII in use.
#define RX_BUF_NUM (5)
#define TX_BUF_NUM (5)
+#define USE_PBUF_REF_FOR_TX (0)
+#else
+// RGMII in use, so increase number of buffers and use pbuf zero copy if possible.
+#define RX_BUF_NUM (16)
+#define TX_BUF_NUM (16)
+#define USE_PBUF_REF_FOR_TX (1)
+#endif
+
+#if defined(STM32N6)
+// The N6 has two DMA channels, so use one for RX and one for TX.
+#define RX_DMA_CH (0)
+#define TX_DMA_CH (1)
+#endif
typedef struct _eth_dma_rx_descr_t {
volatile uint32_t rdes0, rdes1, rdes2, rdes3;
@@ -106,11 +141,18 @@ typedef struct _eth_dma_tx_descr_t {
typedef struct _eth_dma_t {
eth_dma_rx_descr_t rx_descr[RX_BUF_NUM];
eth_dma_tx_descr_t tx_descr[TX_BUF_NUM];
- uint8_t rx_buf[RX_BUF_NUM * RX_BUF_SIZE] __attribute__((aligned(4)));
- uint8_t tx_buf[TX_BUF_NUM * TX_BUF_SIZE] __attribute__((aligned(4)));
- size_t rx_descr_idx;
- size_t tx_descr_idx;
- uint8_t padding[16384 - 15408];
+ uint8_t rx_buf[RX_BUF_NUM * RX_BUF_SIZE] __attribute__((aligned(8)));
+ #if !USE_PBUF_REF_FOR_TX
+ uint8_t tx_buf[TX_BUF_NUM * TX_BUF_SIZE] __attribute__((aligned(8)));
+ #endif
+ #if !defined(STM32H5) && !defined(STM32N6)
+ // Make sure the size of this struct is 16k, for the MPU.
+ uint8_t padding[16 * 1024
+ - sizeof(eth_dma_rx_descr_t) * RX_BUF_NUM
+ - sizeof(eth_dma_tx_descr_t) * TX_BUF_NUM
+ - RX_BUF_NUM * RX_BUF_SIZE
+ - TX_BUF_NUM * TX_BUF_SIZE];
+ #endif
} eth_dma_t;
typedef struct _eth_t {
@@ -118,18 +160,30 @@ typedef struct _eth_t {
struct netif netif;
struct dhcp dhcp_struct;
uint32_t phy_addr;
+ void (*phy_init)(uint32_t phy_addr);
int16_t (*phy_get_link_status)(uint32_t phy_addr);
} eth_t;
+// This struct contains RX and TX buffers shared with the DMA, and they may need
+// to go in a special RAM section, or have MPU settings applied.
static eth_dma_t eth_dma MICROPY_HW_ETH_DMA_ATTRIBUTE;
+#if USE_PBUF_REF_FOR_TX
+// This array holds lwIP pbufs that are currently in use by the DMA.
+static struct pbuf *eth_dma_pbuf[TX_BUF_NUM];
+#endif
+
+// These variables index the buffers in eth_dma and are not shared with DMA.
+static size_t eth_dma_rx_descr_idx;
+static size_t eth_dma_tx_descr_idx;
+
eth_t eth_instance;
static void eth_mac_deinit(eth_t *self);
static void eth_process_frame(eth_t *self, size_t len, const uint8_t *buf);
void eth_phy_write(uint32_t phy_addr, uint32_t reg, uint32_t val) {
- #if defined(STM32H5) || defined(STM32H7)
+ #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
while (ETH->MACMDIOAR & ETH_MACMDIOAR_MB) {
}
uint32_t ar = ETH->MACMDIOAR;
@@ -157,7 +211,7 @@ void eth_phy_write(uint32_t phy_addr, uint32_t reg, uint32_t val) {
}
uint32_t eth_phy_read(uint32_t phy_addr, uint32_t reg) {
- #if defined(STM32H5) || defined(STM32H7)
+ #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
while (ETH->MACMDIOAR & ETH_MACMDIOAR_MB) {
}
uint32_t ar = ETH->MACMDIOAR;
@@ -188,24 +242,47 @@ int eth_init(eth_t *self, int mac_idx, uint32_t phy_addr, int phy_type) {
mp_hal_get_mac(mac_idx, &self->netif.hwaddr[0]);
self->netif.hwaddr_len = 6;
self->phy_addr = phy_addr;
+ self->phy_init = eth_phy_generic_init;
if (phy_type == ETH_PHY_DP83825 || phy_type == ETH_PHY_DP83848) {
self->phy_get_link_status = eth_phy_dp838xx_get_link_status;
} else if (phy_type == ETH_PHY_LAN8720 || phy_type == ETH_PHY_LAN8742) {
self->phy_get_link_status = eth_phy_lan87xx_get_link_status;
+ } else if (phy_type == ETH_PHY_RTL8211) {
+ self->phy_init = eth_phy_rtl8211_init;
+ self->phy_get_link_status = eth_phy_rtl8211_get_link_status;
} else {
return -1;
}
- // Configure GPIO
- mp_hal_pin_config_alt_static(MICROPY_HW_ETH_MDC, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_MDC);
- mp_hal_pin_config_alt_static(MICROPY_HW_ETH_MDIO, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_MDIO);
- mp_hal_pin_config_alt_static_speed(MICROPY_HW_ETH_RMII_REF_CLK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_MEDIUM, STATIC_AF_ETH_RMII_REF_CLK);
- mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RMII_CRS_DV, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_RMII_CRS_DV);
- mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RMII_RXD0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_RMII_RXD0);
- mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RMII_RXD1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_RMII_RXD1);
- mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RMII_TX_EN, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_RMII_TX_EN);
- mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RMII_TXD0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_RMII_TXD0);
- mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RMII_TXD1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_RMII_TXD1);
+ // Configure GPIO for management data.
+ mp_hal_pin_config_alt_static(MICROPY_HW_ETH_MDC, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH(MDC));
+ mp_hal_pin_config_alt_static(MICROPY_HW_ETH_MDIO, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH(MDIO));
+
+ #if defined(MICROPY_HW_ETH_RMII_REF_CLK)
+ // Configure GPIO for RMII interface.
+ mp_hal_pin_config_alt_static_speed(MICROPY_HW_ETH_RMII_REF_CLK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_MEDIUM, STATIC_AF_ETH(RMII_REF_CLK));
+ mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RMII_CRS_DV, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH(RMII_CRS_DV));
+ mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RMII_RXD0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH(RMII_RXD0));
+ mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RMII_RXD1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH(RMII_RXD1));
+ mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RMII_TX_EN, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH(RMII_TX_EN));
+ mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RMII_TXD0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH(RMII_TXD0));
+ mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RMII_TXD1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH(RMII_TXD1));
+ #else
+ // Configure GPIO for RGMII interface.
+ mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RGMII_CLK125, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH(RGMII_CLK125));
+ mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RGMII_GTX_CLK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH(RGMII_GTX_CLK));
+ mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RGMII_TXD0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH(RGMII_TXD0));
+ mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RGMII_TXD1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH(RGMII_TXD1));
+ mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RGMII_TXD2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH(RGMII_TXD2));
+ mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RGMII_TXD3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH(RGMII_TXD3));
+ mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RGMII_TX_CTL, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH(RGMII_TX_CTL));
+ mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RGMII_RX_CLK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH(RGMII_RX_CLK));
+ mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RGMII_RXD0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH(RGMII_RXD0));
+ mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RGMII_RXD1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH(RGMII_RXD1));
+ mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RGMII_RXD2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH(RGMII_RXD2));
+ mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RGMII_RXD3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH(RGMII_RXD3));
+ mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RGMII_RX_CTL, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH(RGMII_RX_CTL));
+ #endif
// Enable peripheral clock
#if defined(STM32H5)
@@ -216,6 +293,11 @@ int eth_init(eth_t *self, int mac_idx, uint32_t phy_addr, int phy_type) {
__HAL_RCC_ETH1MAC_CLK_ENABLE();
__HAL_RCC_ETH1TX_CLK_ENABLE();
__HAL_RCC_ETH1RX_CLK_ENABLE();
+ #elif defined(STM32N6)
+ __HAL_RCC_ETH1_CLK_ENABLE();
+ __HAL_RCC_ETH1MAC_CLK_ENABLE();
+ __HAL_RCC_ETH1TX_CLK_ENABLE();
+ __HAL_RCC_ETH1RX_CLK_ENABLE();
#else
__HAL_RCC_ETH_CLK_ENABLE();
#endif
@@ -229,9 +311,10 @@ void eth_set_trace(eth_t *self, uint32_t value) {
static int eth_mac_init(eth_t *self) {
// Configure MPU
uint32_t irq_state = mpu_config_start();
- #if defined(STM32H5)
- mpu_config_region(MPU_REGION_ETH, (uint32_t)&eth_dma, MPU_CONFIG_ETH(16 * 1024));
+ #if defined(STM32H5) || defined(STM32N6)
+ mpu_config_region(MPU_REGION_ETH, (uint32_t)&eth_dma, MPU_CONFIG_ETH(sizeof(eth_dma_t)));
#else
+ MP_STATIC_ASSERT(sizeof(eth_dma_t) == 16 * 1024);
mpu_config_region(MPU_REGION_ETH, (uint32_t)&eth_dma, MPU_CONFIG_ETH(MPU_REGION_SIZE_16KB));
#endif
mpu_config_end(irq_state);
@@ -241,16 +324,33 @@ static int eth_mac_init(eth_t *self) {
__HAL_RCC_ETH_FORCE_RESET();
#elif defined(STM32H7)
__HAL_RCC_ETH1MAC_FORCE_RESET();
+ #elif defined(STM32N6)
+ __HAL_RCC_ETH1_FORCE_RESET();
#else
__HAL_RCC_ETHMAC_FORCE_RESET();
#endif
- // Select RMII interface
+ // Select clock sources.
+ #if defined(STM32N6)
+ LL_RCC_SetETHREFTXClockSource(LL_RCC_ETH1REFTX_CLKSOURCE_EXT); // max 25MHz
+ LL_RCC_SetETHREFRXClockSource(LL_RCC_ETH1REFRX_CLKSOURCE_EXT); // max 125MHz
+ LL_RCC_SetETHClockSource(LL_RCC_ETH1_CLKSOURCE_IC12); // max 125MHz
+ LL_RCC_SetETH1PTPDivider(LL_RCC_ETH1PTP_DIV_1);
+ LL_RCC_SetETHPTPClockSource(LL_RCC_ETH1PTP_CLKSOURCE_HCLK); // max 200MHz
+ #endif
+
+ // Select RMII or RGMII interface
#if defined(STM32H5)
__HAL_RCC_SBS_CLK_ENABLE();
SBS->PMCR = (SBS->PMCR & ~SBS_PMCR_ETH_SEL_PHY_Msk) | SBS_PMCR_ETH_SEL_PHY_2;
#elif defined(STM32H7)
SYSCFG->PMCR = (SYSCFG->PMCR & ~SYSCFG_PMCR_EPIS_SEL_Msk) | SYSCFG_PMCR_EPIS_SEL_2;
+ #elif defined(STM32N6)
+ #if defined(MICROPY_HW_ETH_RGMII_CLK125)
+ LL_RCC_SetETHPHYInterface(LL_RCC_ETH1PHY_IF_RGMII);
+ #else
+ LL_RCC_SetETHPHYInterface(LL_RCC_ETH1PHY_IF_RMII);
+ #endif
#else
__HAL_RCC_SYSCFG_CLK_ENABLE();
SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL;
@@ -268,6 +368,13 @@ static int eth_mac_init(eth_t *self) {
__HAL_RCC_ETH1MAC_CLK_SLEEP_ENABLE();
__HAL_RCC_ETH1TX_CLK_SLEEP_ENABLE();
__HAL_RCC_ETH1RX_CLK_SLEEP_ENABLE();
+ #elif defined(STM32N6)
+ __HAL_RCC_ETH1_RELEASE_RESET();
+
+ __HAL_RCC_ETH1_CLK_SLEEP_ENABLE();
+ __HAL_RCC_ETH1MAC_CLK_SLEEP_ENABLE();
+ __HAL_RCC_ETH1TX_CLK_SLEEP_ENABLE();
+ __HAL_RCC_ETH1RX_CLK_SLEEP_ENABLE();
#else
__HAL_RCC_ETHMAC_RELEASE_RESET();
@@ -277,7 +384,7 @@ static int eth_mac_init(eth_t *self) {
#endif
// Do a soft reset of the MAC core
- #if defined(STM32H5) || defined(STM32H7)
+ #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
#define ETH_SOFT_RESET(eth) do { eth->DMAMR = ETH_DMAMR_SWR; } while (0)
#define ETH_IS_RESET(eth) (eth->DMAMR & ETH_DMAMR_SWR)
#else
@@ -299,7 +406,7 @@ static int eth_mac_init(eth_t *self) {
// Set MII clock range
uint32_t hclk = HAL_RCC_GetHCLKFreq();
uint32_t cr_div;
- #if defined(STM32H5)
+ #if defined(STM32H5) || defined(STM32N6)
cr_div = ETH->MACMDIOAR & ~ETH_MACMDIOAR_CR;
if (hclk < 35000000) {
cr_div |= ETH_MACMDIOAR_CR_DIV16;
@@ -311,8 +418,17 @@ static int eth_mac_init(eth_t *self) {
cr_div |= ETH_MACMDIOAR_CR_DIV62;
} else if (hclk < 250000000) {
cr_div |= ETH_MACMDIOAR_CR_DIV102;
+ #if defined(STM32H5)
} else {
cr_div |= ETH_MACMDIOAR_CR_DIV124;
+ #else
+ } else if (hclk < 300000000) {
+ cr_div |= ETH_MACMDIOAR_CR_DIV124;
+ } else if (hclk < 500000000) {
+ cr_div |= ETH_MACMDIOAR_CR_DIV204;
+ } else {
+ cr_div |= ETH_MACMDIOAR_CR_DIV324;
+ #endif
}
ETH->MACMDIOAR = cr_div;
#elif defined(STM32H7)
@@ -344,14 +460,21 @@ static int eth_mac_init(eth_t *self) {
ETH->MACMIIAR = cr_div;
#endif
+ #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
+ // Configure the MAC 1-us tick counter register.
+ WRITE_REG(ETH->MAC1USTCR, HAL_RCC_GetHCLKFreq() / 1000000U - 1U);
+ #endif
+
#if defined(STM32H5) || defined(STM32H7)
// don't skip 32bit words since our descriptors are continuous in memory
ETH->DMACCR &= ~(ETH_DMACCR_DSL_Msk);
+ #elif defined(STM32N6)
+ ETH->DMA_CH[RX_DMA_CH].DMACCR &= ~(ETH_DMACxCR_DSL_Msk);
+ ETH->DMA_CH[TX_DMA_CH].DMACCR &= ~(ETH_DMACxCR_DSL_Msk);
#endif
- // Reset the PHY
- eth_phy_write(self->phy_addr, PHY_BCR, PHY_BCR_SOFT_RESET);
- mp_hal_delay_ms(50);
+ // Reset and initialize the PHY.
+ self->phy_init(self->phy_addr);
// Wait for the PHY link to be established
int phy_state = 0;
@@ -397,7 +520,7 @@ static int eth_mac_init(eth_t *self) {
uint16_t phy_scsr = self->phy_get_link_status(self->phy_addr);
// Burst mode configuration
- #if defined(STM32H5) || defined(STM32H7)
+ #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
ETH->DMASBMR = ETH->DMASBMR & ~ETH_DMASBMR_AAL & ~ETH_DMASBMR_FB;
#else
ETH->DMABMR = 0;
@@ -410,6 +533,21 @@ static int eth_mac_init(eth_t *self) {
| ETH_DMACIER_NIE // enable normal interrupts
| ETH_DMACIER_RIE // enable RX interrupt
;
+ #elif defined(STM32N6)
+ ETH->DMA_CH[RX_DMA_CH].DMACIER =
+ ETH_DMACxIER_NIE // enable normal interrupts
+ | ETH_DMACxIER_RIE // enable RX interrupt
+ ;
+ #if USE_PBUF_REF_FOR_TX
+ #if RX_DMA_CH == TX_DMA_CH
+ ETH->DMA_CH[TX_DMA_CH].DMACIER |= ETH_DMACxIER_TIE; // enable TX interrupt
+ #else
+ ETH->DMA_CH[TX_DMA_CH].DMACIER =
+ ETH_DMACxIER_NIE // enable normal interrupts
+ | ETH_DMACxIER_TIE // enable TX interrupt
+ ;
+ #endif
+ #endif
#else
ETH->DMAIER =
ETH_DMAIER_NISE // enable normal interrupts
@@ -419,7 +557,7 @@ static int eth_mac_init(eth_t *self) {
// Configure RX descriptor lists
for (size_t i = 0; i < RX_BUF_NUM; ++i) {
- #if defined(STM32H5) || defined(STM32H7)
+ #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
eth_dma.rx_descr[i].rdes3 =
1 << RX_DESCR_3_OWN_Pos
| (1 << RX_DESCR_3_BUF1V_Pos) // buf1 address valid
@@ -439,17 +577,22 @@ static int eth_mac_init(eth_t *self) {
#if defined(STM32H5) || defined(STM32H7)
ETH->DMACRDLAR = (uint32_t)&eth_dma.rx_descr[0];
+ #elif defined(STM32N6)
+ // Set number of RX descriptors and buffer pointers.
+ ETH->DMA_CH[RX_DMA_CH].DMACRXRLR = RX_BUF_NUM - 1;
+ ETH->DMA_CH[RX_DMA_CH].DMACRXDLAR = (uint32_t)&eth_dma.rx_descr[0];
+ ETH->DMA_CH[RX_DMA_CH].DMACRXDTPR = (uint32_t)&eth_dma.rx_descr[RX_BUF_NUM - 1];
#else
ETH->DMARDLAR = (uint32_t)&eth_dma.rx_descr[0];
#endif
- eth_dma.rx_descr_idx = 0;
+ eth_dma_rx_descr_idx = 0;
// Configure TX descriptor lists
for (size_t i = 0; i < TX_BUF_NUM; ++i) {
- #if defined(STM32H5) || defined(STM32H7)
+ #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
eth_dma.tx_descr[i].tdes0 = 0;
eth_dma.tx_descr[i].tdes1 = 0;
- eth_dma.tx_descr[i].tdes2 = TX_BUF_SIZE & TX_DESCR_2_B1L_Msk;
+ eth_dma.tx_descr[i].tdes2 = 0;
eth_dma.tx_descr[i].tdes3 = 0;
#else
eth_dma.tx_descr[i].tdes0 = 1 << TX_DESCR_0_TCH_Pos;
@@ -465,10 +608,20 @@ static int eth_mac_init(eth_t *self) {
ETH->DMACRDRLR = RX_BUF_NUM - 1;
ETH->DMACTDLAR = (uint32_t)&eth_dma.tx_descr[0];
+ #elif defined(STM32N6)
+ // Set number of TX descriptors and buffer pointers.
+ ETH->DMA_CH[TX_DMA_CH].DMACTXRLR = TX_BUF_NUM - 1;
+ ETH->DMA_CH[TX_DMA_CH].DMACTXDLAR = (uint32_t)&eth_dma.tx_descr[0];
+ ETH->DMA_CH[TX_DMA_CH].DMACTXDTPR = (uint32_t)&eth_dma.tx_descr[0];
#else
ETH->DMATDLAR = (uint32_t)&eth_dma.tx_descr[0];
#endif
- eth_dma.tx_descr_idx = 0;
+ eth_dma_tx_descr_idx = 0;
+ #if USE_PBUF_REF_FOR_TX
+ for (int i = 0; i < TX_BUF_NUM; ++i) {
+ eth_dma_pbuf[i] = NULL;
+ }
+ #endif
// Configure DMA
#if defined(STM32H5) || defined(STM32H7)
@@ -476,6 +629,11 @@ static int eth_mac_init(eth_t *self) {
ETH->MTLRQOMR = ETH_MTLRQOMR_RSF;
// transmission starts when a full packet resides in the Tx queue
ETH->MTLTQOMR = ETH_MTLTQOMR_TSF;
+ #elif defined(STM32N6)
+ // read from RX FIFO only after a full frame is written
+ ETH->MTL_QUEUE[0].MTLRXQOMR = ETH_MTLRXQxOMR_RSF;
+ // transmission starts when a full packet resides in the Tx queue
+ ETH->MTL_QUEUE[0].MTLTXQOMR = ETH_MTLTXQxOMR_TSF;
#else
ETH->DMAOMR =
ETH_DMAOMR_RSF // read from RX FIFO after a full frame is written
@@ -485,7 +643,7 @@ static int eth_mac_init(eth_t *self) {
mp_hal_delay_ms(2);
// Select MAC filtering options
- #if defined(STM32H5) || defined(STM32H7)
+ #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
ETH->MACPFR = ETH_MACPFR_RA; // pass all frames up
#else
ETH->MACFFR =
@@ -501,15 +659,50 @@ static int eth_mac_init(eth_t *self) {
ETH->MACA0LR = mac[3] << 24 | mac[2] << 16 | mac[1] << 8 | mac[0];
mp_hal_delay_ms(2);
+ // Work out the line speed configuration for MACCR.
+ uint32_t maccr = 0;
+ if (phy_scsr & PHY_SPEED_100HALF) {
+ maccr |= ETH_MACCR_FES;
+ }
+ if (phy_scsr & PHY_DUPLEX) {
+ maccr |= ETH_MACCR_DM;
+ }
+
+ #if defined(STM32N6)
+
+ if (!(phy_scsr & PHY_SPEED_1000HALF)) {
+ maccr |= ETH_MACCR_PS;
+ }
+
+ maccr |=
+ ETH_MACCR_IPG_96BIT
+ | ETH_MACCR_SARC_REPADDR0
+ | ETH_MACCR_IPC
+ | ETH_MACCR_BL_10
+ | ETH_MACCR_PRELEN_7;
+
+ ETH->MACCR = maccr;
+ ETH->MACECR = 0x618U;
+ ETH->MACWTR = ETH_MACWTR_WTO_2KB;
+ ETH->MACQ0TXFCR = ETH_MACQ0TXFCR_PLT_MINUS4;
+ ETH->MACRXFCR = 0;
+ ETH->MACRXQC0R = ETH_MACRXQC0R_RXQ0EN_GT | ETH_MACRXQC0R_RXQ1EN_NOT;
+
+ ETH->MTLOMR = ETH_MTLOMR_SCHALG_SP | ETH_MTLOMR_RAA_SP;
+ ETH->MTLRXQDMAMR = ETH_MTLRXQDMAMR_Q0MDMACH_DMACH0 | ETH_MTLRXQDMAMR_Q1MDMACH_DMACH1;
+ ETH->MTL_QUEUE[0].MTLTXQOMR = ETH_MTLTXQxOMR_TXQEN_EN | ETH_MTLTXQxOMR_TSF | 7 << ETH_MTLTXQxOMR_TQS_Pos;
+ ETH->MTL_QUEUE[1].MTLTXQOMR = ETH_MTLTXQxOMR_TXQEN_EN | ETH_MTLTXQxOMR_TSF | 7 << ETH_MTLTXQxOMR_TQS_Pos;
+ ETH->MTL_QUEUE[0].MTLRXQOMR = ETH_MTLRXQxOMR_RSF | 15 << ETH_MTLRXQxOMR_RQS_Pos;
+ ETH->MTL_QUEUE[1].MTLRXQOMR = ETH_MTLRXQxOMR_RSF | 15 << ETH_MTLRXQxOMR_RQS_Pos;
+
+ #else
+
// Set main MAC control register
- ETH->MACCR =
- phy_scsr == PHY_SPEED_10FULL ? ETH_MACCR_DM
- : phy_scsr == PHY_SPEED_100HALF ? ETH_MACCR_FES
- : phy_scsr == PHY_SPEED_100FULL ? (ETH_MACCR_FES | ETH_MACCR_DM)
- : 0
- ;
+ ETH->MACCR = maccr;
mp_hal_delay_ms(2);
+ #endif
+
// Start MAC layer
ETH->MACCR |=
ETH_MACCR_TE // enable TX
@@ -521,6 +714,15 @@ static int eth_mac_init(eth_t *self) {
#if defined(STM32H5) || defined(STM32H7)
ETH->DMACRCR |= ETH_DMACRCR_SR; // start RX
ETH->DMACTCR |= ETH_DMACTCR_ST; // start TX
+ #elif defined(STM32N6)
+ ETH->MTL_QUEUE[0].MTLTXQOMR |= ETH_MTLTXQxOMR_FTQ; // flush TX FIFO
+ ETH->MTL_QUEUE[1].MTLTXQOMR |= ETH_MTLTXQxOMR_FTQ; // flush TX FIFO
+ ETH->DMA_CH[RX_DMA_CH].DMACRXCR = RX_BUF_SIZE << ETH_DMACxRXCR_RBSZ_Pos;
+ ETH->DMA_CH[RX_DMA_CH].DMACRXCR |= ETH_DMACxRXCR_SR; // start RX
+ ETH->DMA_CH[TX_DMA_CH].DMACTXCR = 4 << ETH_DMACxTXCR_TXPBL_Pos;
+ ETH->DMA_CH[TX_DMA_CH].DMACTXCR |= ETH_DMACxTXCR_ST; // start TX
+ ETH->DMA_CH[RX_DMA_CH].DMACSR |= ETH_DMACxSR_TPS | ETH_DMACxSR_RPS; // clear TX/RX process stopped flags
+ ETH->DMA_CH[TX_DMA_CH].DMACSR |= ETH_DMACxSR_TPS | ETH_DMACxSR_RPS; // clear TX/RX process stopped flags
#else
ETH->DMAOMR |=
ETH_DMAOMR_ST // start TX
@@ -547,6 +749,10 @@ static void eth_mac_deinit(eth_t *self) {
__HAL_RCC_ETH1MAC_FORCE_RESET();
__HAL_RCC_ETH1MAC_RELEASE_RESET();
__HAL_RCC_ETH1MAC_CLK_DISABLE();
+ #elif defined(STM32N6)
+ __HAL_RCC_ETH1_FORCE_RESET();
+ __HAL_RCC_ETH1_RELEASE_RESET();
+ __HAL_RCC_ETH1_CLK_DISABLE();
#else
__HAL_RCC_ETHMAC_FORCE_RESET();
__HAL_RCC_ETHMAC_RELEASE_RESET();
@@ -554,16 +760,18 @@ static void eth_mac_deinit(eth_t *self) {
#endif
}
-static int eth_tx_buf_get(size_t len, uint8_t **buf) {
+#if !USE_PBUF_REF_FOR_TX
+
+int eth_tx_buf_get(size_t len, uint8_t **buf) {
if (len > TX_BUF_SIZE) {
return -MP_EINVAL;
}
// Wait for DMA to release the current TX descriptor (if it has it)
- eth_dma_tx_descr_t *tx_descr = &eth_dma.tx_descr[eth_dma.tx_descr_idx];
+ eth_dma_tx_descr_t *tx_descr = &eth_dma.tx_descr[eth_dma_tx_descr_idx];
uint32_t t0 = mp_hal_ticks_ms();
for (;;) {
- #if defined(STM32H5) || defined(STM32H7)
+ #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
if (!(tx_descr->tdes3 & (1 << TX_DESCR_3_OWN_Pos))) {
break;
}
@@ -577,44 +785,67 @@ static int eth_tx_buf_get(size_t len, uint8_t **buf) {
}
}
- #if defined(STM32H5) || defined(STM32H7)
+ #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
// Update TX descriptor with length and buffer pointer
- *buf = &eth_dma.tx_buf[eth_dma.tx_descr_idx * TX_BUF_SIZE];
+ *buf = &eth_dma.tx_buf[eth_dma_tx_descr_idx * TX_BUF_SIZE];
tx_descr->tdes2 = len & TX_DESCR_2_B1L_Msk;
tx_descr->tdes0 = (uint32_t)*buf;
#else
// Update TX descriptor with length, buffer pointer and linked list pointer
- *buf = &eth_dma.tx_buf[eth_dma.tx_descr_idx * TX_BUF_SIZE];
+ *buf = &eth_dma.tx_buf[eth_dma_tx_descr_idx * TX_BUF_SIZE];
tx_descr->tdes1 = len << TX_DESCR_1_TBS1_Pos;
tx_descr->tdes2 = (uint32_t)*buf;
- tx_descr->tdes3 = (uint32_t)&eth_dma.tx_descr[(eth_dma.tx_descr_idx + 1) % TX_BUF_NUM];
+ tx_descr->tdes3 = (uint32_t)&eth_dma.tx_descr[(eth_dma_tx_descr_idx + 1) % TX_BUF_NUM];
#endif
return 0;
}
-static int eth_tx_buf_send(void) {
- // Get TX descriptor and move to next one
- eth_dma_tx_descr_t *tx_descr = &eth_dma.tx_descr[eth_dma.tx_descr_idx];
- eth_dma.tx_descr_idx = (eth_dma.tx_descr_idx + 1) % TX_BUF_NUM;
+#else
- // Schedule to send next outgoing frame
- #if defined(STM32H5) || defined(STM32H7)
- tx_descr->tdes3 =
- 1 << TX_DESCR_3_OWN_Pos // owned by DMA
- | 1 << TX_DESCR_3_LD_Pos // last segment
- | 1 << TX_DESCR_3_FD_Pos // first segment
- | 3 << TX_DESCR_3_CIC_Pos // enable all checksums inserted by hardware
- ;
- #else
- tx_descr->tdes0 =
- 1 << TX_DESCR_0_OWN_Pos // owned by DMA
- | 1 << TX_DESCR_0_LS_Pos // last segment
- | 1 << TX_DESCR_0_FS_Pos // first segment
- | 3 << TX_DESCR_0_CIC_Pos // enable all checksums inserted by hardware
- | 1 << TX_DESCR_0_TCH_Pos // TX descriptor is chained
- ;
- #endif
+int eth_tx_buf_get_ref(size_t len, uint8_t *buf, unsigned int idx) {
+ // Wait for DMA to release the current TX descriptor (if it has it).
+ eth_dma_tx_descr_t *tx_descr = &eth_dma.tx_descr[(eth_dma_tx_descr_idx + idx) % TX_BUF_NUM];
+ uint32_t t0 = mp_hal_ticks_ms();
+ while (tx_descr->tdes3 & (1 << TX_DESCR_3_OWN_Pos)) {
+ if (mp_hal_ticks_ms() - t0 > 1000) {
+ return -MP_ETIMEDOUT;
+ }
+ }
+
+ MP_HAL_CLEAN_DCACHE(buf, len);
+ tx_descr->tdes2 = (len & TX_DESCR_2_B1L_Msk) | (1 << TX_DESCR_2_IOC_Pos);
+ tx_descr->tdes0 = (uint32_t)buf;
+
+ return 0;
+}
+
+#endif
+
+static int eth_tx_buf_send(unsigned int num_segments) {
+ for (unsigned int segment = 0; segment < num_segments; ++segment) {
+ // Get TX descriptor and move to next one
+ eth_dma_tx_descr_t *tx_descr = &eth_dma.tx_descr[eth_dma_tx_descr_idx];
+ eth_dma_tx_descr_idx = (eth_dma_tx_descr_idx + 1) % TX_BUF_NUM;
+
+ // Schedule to send next outgoing frame
+ #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
+ tx_descr->tdes3 =
+ 1 << TX_DESCR_3_OWN_Pos // owned by DMA
+ | (segment == num_segments - 1) << TX_DESCR_3_LD_Pos // last segment
+ | (segment == 0) << TX_DESCR_3_FD_Pos // first segment
+ | 3 << TX_DESCR_3_CIC_Pos // enable all checksums inserted by hardware
+ ;
+ #else
+ tx_descr->tdes0 =
+ 1 << TX_DESCR_0_OWN_Pos // owned by DMA
+ | (segment == num_segments - 1) << TX_DESCR_0_LS_Pos // last segment
+ | (segment == 0) << TX_DESCR_0_FS_Pos // first segment
+ | 3 << TX_DESCR_0_CIC_Pos // enable all checksums inserted by hardware
+ | 1 << TX_DESCR_0_TCH_Pos // TX descriptor is chained
+ ;
+ #endif
+ }
// Notify ETH DMA that there is a new TX descriptor for sending
__DMB();
@@ -622,7 +853,12 @@ static int eth_tx_buf_send(void) {
if (ETH->DMACSR & ETH_DMACSR_TBU) {
ETH->DMACSR = ETH_DMACSR_TBU;
}
- ETH->DMACTDTPR = (uint32_t)&eth_dma.tx_descr[eth_dma.tx_descr_idx];
+ ETH->DMACTDTPR = (uint32_t)&eth_dma.tx_descr[eth_dma_tx_descr_idx];
+ #elif defined(STM32N6)
+ if (ETH->DMA_CH[TX_DMA_CH].DMACSR & ETH_DMACxSR_TBU) {
+ ETH->DMA_CH[TX_DMA_CH].DMACSR = ETH_DMACxSR_TBU;
+ }
+ ETH->DMA_CH[TX_DMA_CH].DMACTXDTPR = (uint32_t)&eth_dma.tx_descr[eth_dma_tx_descr_idx];
#else
if (ETH->DMASR & ETH_DMASR_TBUS) {
ETH->DMASR = ETH_DMASR_TBUS;
@@ -635,12 +871,12 @@ static int eth_tx_buf_send(void) {
static void eth_dma_rx_free(void) {
// Get RX descriptor, RX buffer and move to next one
- eth_dma_rx_descr_t *rx_descr = &eth_dma.rx_descr[eth_dma.rx_descr_idx];
- uint8_t *buf = &eth_dma.rx_buf[eth_dma.rx_descr_idx * RX_BUF_SIZE];
- eth_dma.rx_descr_idx = (eth_dma.rx_descr_idx + 1) % RX_BUF_NUM;
+ eth_dma_rx_descr_t *rx_descr = &eth_dma.rx_descr[eth_dma_rx_descr_idx];
+ uint8_t *buf = &eth_dma.rx_buf[eth_dma_rx_descr_idx * RX_BUF_SIZE];
+ eth_dma_rx_descr_idx = (eth_dma_rx_descr_idx + 1) % RX_BUF_NUM;
// Schedule to get next incoming frame
- #if defined(STM32H5) || defined(STM32H7)
+ #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
rx_descr->rdes0 = (uint32_t)buf;
rx_descr->rdes3 = 1 << RX_DESCR_3_OWN_Pos; // owned by DMA
rx_descr->rdes3 |= 1 << RX_DESCR_3_BUF1V_Pos; // buf 1 address valid
@@ -651,24 +887,32 @@ static void eth_dma_rx_free(void) {
| RX_BUF_SIZE << RX_DESCR_1_RBS1_Pos // maximum buffer length
;
rx_descr->rdes2 = (uint32_t)buf;
- rx_descr->rdes3 = (uint32_t)&eth_dma.rx_descr[eth_dma.rx_descr_idx];
+ rx_descr->rdes3 = (uint32_t)&eth_dma.rx_descr[eth_dma_rx_descr_idx];
rx_descr->rdes0 = 1 << RX_DESCR_0_OWN_Pos; // owned by DMA
#endif
// Notify ETH DMA that there is a new RX descriptor available
__DMB();
#if defined(STM32H5) || defined(STM32H7)
- ETH->DMACRDTPR = (uint32_t)&rx_descr[eth_dma.rx_descr_idx];
+ ETH->DMACRDTPR = (uint32_t)&rx_descr[eth_dma_rx_descr_idx];
+ #elif defined(STM32N6)
+ ETH->DMA_CH[RX_DMA_CH].DMACRXDTPR = (uint32_t)&rx_descr[eth_dma_rx_descr_idx];
#else
ETH->DMARPDR = 0;
#endif
}
void ETH_IRQHandler(void) {
+ MP_STATIC_ASSERT(ETH_IRQn > 0);
+
#if defined(STM32H5) || defined(STM32H7)
uint32_t sr = ETH->DMACSR;
ETH->DMACSR = ETH_DMACSR_NIS;
uint32_t rx_interrupt = sr & ETH_DMACSR_RI;
+ #elif defined(STM32N6)
+ uint32_t sr = ETH->DMA_CH[RX_DMA_CH].DMACSR;
+ ETH->DMA_CH[RX_DMA_CH].DMACSR = ETH_DMACxSR_NIS;
+ uint32_t rx_interrupt = sr & ETH_DMACxSR_RI;
#else
uint32_t sr = ETH->DMASR;
ETH->DMASR = ETH_DMASR_NIS;
@@ -677,18 +921,20 @@ void ETH_IRQHandler(void) {
if (rx_interrupt) {
#if defined(STM32H5) || defined(STM32H7)
ETH->DMACSR = ETH_DMACSR_RI;
+ #elif defined(STM32N6)
+ ETH->DMA_CH[RX_DMA_CH].DMACSR = ETH_DMACxSR_RI;
#else
ETH->DMASR = ETH_DMASR_RS;
#endif
for (;;) {
- #if defined(STM32H5) || defined(STM32H7)
- eth_dma_rx_descr_t *rx_descr_l = &eth_dma.rx_descr[eth_dma.rx_descr_idx];
+ #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
+ eth_dma_rx_descr_t *rx_descr_l = &eth_dma.rx_descr[eth_dma_rx_descr_idx];
if (rx_descr_l->rdes3 & (1 << RX_DESCR_3_OWN_Pos)) {
// No more RX descriptors ready to read
break;
}
#else
- eth_dma_rx_descr_t *rx_descr = &eth_dma.rx_descr[eth_dma.rx_descr_idx];
+ eth_dma_rx_descr_t *rx_descr = &eth_dma.rx_descr[eth_dma_rx_descr_idx];
if (rx_descr->rdes0 & (1 << RX_DESCR_0_OWN_Pos)) {
// No more RX descriptors ready to read
break;
@@ -696,14 +942,14 @@ void ETH_IRQHandler(void) {
#endif
// Get RX buffer containing new frame
- #if defined(STM32H5) || defined(STM32H7)
+ #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
size_t len = (rx_descr_l->rdes3 & RX_DESCR_3_PL_Msk);
#else
size_t len = (rx_descr->rdes0 & RX_DESCR_0_FL_Msk) >> RX_DESCR_0_FL_Pos;
#endif
len -= 4; // discard CRC at end
- #if defined(STM32H5) || defined(STM32H7)
- uint8_t *buf = &eth_dma.rx_buf[eth_dma.rx_descr_idx * RX_BUF_SIZE];
+ #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
+ uint8_t *buf = &eth_dma.rx_buf[eth_dma_rx_descr_idx * RX_BUF_SIZE];
#else
uint8_t *buf = (uint8_t *)rx_descr->rdes2;
#endif
@@ -713,6 +959,28 @@ void ETH_IRQHandler(void) {
eth_dma_rx_free();
}
}
+
+ #if USE_PBUF_REF_FOR_TX
+ #if RX_DMA_CH != TX_DMA_CH
+ sr = ETH->DMA_CH[TX_DMA_CH].DMACSR;
+ ETH->DMA_CH[TX_DMA_CH].DMACSR = ETH_DMACxSR_NIS;
+ #endif
+ uint32_t tx_interrupt = sr & ETH_DMACxSR_TI;
+ if (tx_interrupt) {
+ ETH->DMA_CH[TX_DMA_CH].DMACSR = ETH_DMACxSR_TI;
+ for (int i = 0; i < TX_BUF_NUM; ++i) {
+ eth_dma_tx_descr_t *tx_descr = &eth_dma.tx_descr[i];
+ if (!(tx_descr->tdes3 & (1 << TX_DESCR_3_OWN_Pos))) {
+ // DMA does not own it
+ if (eth_dma_pbuf[i] != NULL) {
+ // release pbuf
+ pbuf_free(eth_dma_pbuf[i]);
+ eth_dma_pbuf[i] = NULL;
+ }
+ }
+ }
+ }
+ #endif
}
/*******************************************************************************/
@@ -749,13 +1017,64 @@ static err_t eth_netif_output(struct netif *netif, struct pbuf *p) {
LINK_STATS_INC(link.xmit);
eth_trace(netif->state, (size_t)-1, p, NETUTILS_TRACE_IS_TX | NETUTILS_TRACE_NEWLINE);
+ #if USE_PBUF_REF_FOR_TX
+
+ // Work out how many segments the pbuf has, and if it needs a copy made.
+ bool made_pbuf_copy = false;
+ unsigned int num_segments = 0;
+ for (struct pbuf *pb = p; pb != NULL; pb = pb->next) {
+ if (PBUF_NEEDS_COPY(pb)) {
+ // Note: this path is called for large UDP packets that are fragmented,
+ // because the fragments use PBUF_REF to divide up the original data.
+ p = pbuf_clone(PBUF_RAW, PBUF_RAM, p);
+ made_pbuf_copy = true;
+ num_segments = 1;
+ break;
+ }
+ ++num_segments;
+ }
+
+ // Allocate TX buffer slots.
+ unsigned int idx = 0;
+ for (struct pbuf *pb = p; pb != NULL; pb = pb->next) {
+ int ret = eth_tx_buf_get_ref(pb->len, pb->payload, idx++);
+ if (ret != 0) {
+ if (made_pbuf_copy) {
+ pbuf_free(p);
+ }
+ return ERR_BUF;
+ }
+ }
+
+ // Take references to pbufs
+ idx = 0;
+ for (struct pbuf *pb = p; pb != NULL; pb = pb->next) {
+ unsigned int tx_idx = (eth_dma_tx_descr_idx + idx) % TX_BUF_NUM;
+ if (eth_dma_pbuf[tx_idx] != NULL) {
+ pbuf_free(eth_dma_pbuf[tx_idx]);
+ }
+ if (!made_pbuf_copy) {
+ pbuf_ref(pb);
+ }
+ eth_dma_pbuf[tx_idx] = pb;
+ ++idx;
+ }
+
+ // Start the transmission.
+ int ret = eth_tx_buf_send(num_segments);
+
+ #else
+
+ // Allocate TX slot, copy the pbuf, and start the transmission.
uint8_t *buf;
int ret = eth_tx_buf_get(p->tot_len, &buf);
if (ret == 0) {
pbuf_copy_partial(p, buf, p->tot_len, 0);
- ret = eth_tx_buf_send();
+ ret = eth_tx_buf_send(1);
}
+ #endif
+
return ret ? ERR_BUF : ERR_OK;
}
@@ -875,6 +1194,8 @@ void eth_low_power_mode(eth_t *self, bool enable) {
// Enable eth clock
#if defined(STM32H7)
__HAL_RCC_ETH1MAC_CLK_ENABLE();
+ #elif defined(STM32N6)
+ __HAL_RCC_ETH1_CLK_ENABLE();
#else
__HAL_RCC_ETH_CLK_ENABLE();
#endif
@@ -886,6 +1207,8 @@ void eth_low_power_mode(eth_t *self, bool enable) {
// Disable eth clock.
#if defined(STM32H7)
__HAL_RCC_ETH1MAC_CLK_DISABLE();
+ #elif defined(STM32N6)
+ __HAL_RCC_ETH1_CLK_DISABLE();
#else
__HAL_RCC_ETH_CLK_DISABLE();
#endif
diff --git a/ports/stm32/eth.h b/ports/stm32/eth.h
index 564744969..6556f4a7c 100644
--- a/ports/stm32/eth.h
+++ b/ports/stm32/eth.h
@@ -30,7 +30,8 @@ enum {
ETH_PHY_LAN8742 = 0,
ETH_PHY_LAN8720,
ETH_PHY_DP83848,
- ETH_PHY_DP83825
+ ETH_PHY_DP83825,
+ ETH_PHY_RTL8211
};
typedef struct _eth_t eth_t;
diff --git a/ports/stm32/eth_phy.c b/ports/stm32/eth_phy.c
index 56cddba9c..cdc632f26 100644
--- a/ports/stm32/eth_phy.c
+++ b/ports/stm32/eth_phy.c
@@ -31,18 +31,45 @@
#if defined(MICROPY_HW_ETH_MDC)
#define PHY_SCSR_LAN87XX (0x001f)
-#define PHY_SCSR_LAN87XX_SPEED_Pos (2)
-#define PHY_SCSR_LAN87XX_SPEED_Msk (7)
+#define PHY_SCSR_LAN87XX_10M_Msk (0x0004)
+#define PHY_SCSR_LAN87XX_100M_Msk (0x0008)
+#define PHY_SCSR_LAN87XX_DUPLEX_Msk (0x0010)
#define PHY_SCSR_DP838XX (0x0010)
#define PHY_RECR_DP838XX (0x0015)
#define PHY_SCSR_DP838XX_DUPLEX_Msk (4)
#define PHY_SCSR_DP838XX_10M_Msk (2)
+#define PHY_RTL8211_DEFAULT_PAGE (0xa42)
+#define PHY_RTL8211_PAGSR_ADDR (0x1f)
+#define PHY_RTL8211_PHYSR_PAGE (0xa43)
+#define PHY_RTL8211_PHYSR_ADDR (0x1a)
+#define PHY_RTL8211_PHYSR_SPEED_Pos (4)
+#define PHY_RTL8211_PHYSR_SPEED_Msk (3 << PHY_RTL8211_PHYSR_SPEED_Pos)
+#define PHY_RTL8211_PHYSR_DUPLEX_Msk (0x0008)
+#define PHY_RTL8211_LCR_PAGE (0xd04)
+#define PHY_RTL8211_LCR_ADDR (0x10)
+
+void eth_phy_generic_init(uint32_t phy_addr) {
+ // Reset the PHY.
+ eth_phy_write(phy_addr, PHY_BCR, PHY_BCR_SOFT_RESET);
+ mp_hal_delay_ms(50);
+}
+
int16_t eth_phy_lan87xx_get_link_status(uint32_t phy_addr) {
// Get the link mode & speed
- int16_t scsr = eth_phy_read(phy_addr, PHY_SCSR_LAN87XX);
- return (scsr >> PHY_SCSR_LAN87XX_SPEED_Pos) & PHY_SCSR_LAN87XX_SPEED_Msk;
+ uint16_t scsr = eth_phy_read(phy_addr, PHY_SCSR_LAN87XX);
+ int16_t status = 0;
+ if (scsr & PHY_SCSR_LAN87XX_10M_Msk) {
+ status |= PHY_SPEED_10HALF;
+ }
+ if (scsr & PHY_SCSR_LAN87XX_100M_Msk) {
+ status |= PHY_SPEED_100HALF;
+ }
+ if (scsr & PHY_SCSR_LAN87XX_DUPLEX_Msk) {
+ status |= PHY_DUPLEX;
+ }
+ return status;
}
int16_t eth_phy_dp838xx_get_link_status(uint32_t phy_addr) {
@@ -56,4 +83,37 @@ int16_t eth_phy_dp838xx_get_link_status(uint32_t phy_addr) {
return scsr;
}
+void eth_phy_rtl8211_init(uint32_t phy_addr) {
+ // Perform generic PHY initialization.
+ eth_phy_generic_init(phy_addr);
+
+ // Configure LED0 output to show 10/100/1000 link speed, and activity.
+ eth_phy_write(phy_addr, PHY_RTL8211_PAGSR_ADDR, PHY_RTL8211_LCR_PAGE);
+ eth_phy_write(phy_addr, PHY_RTL8211_LCR_ADDR, 0x001b);
+ eth_phy_write(phy_addr, PHY_RTL8211_PAGSR_ADDR, PHY_RTL8211_DEFAULT_PAGE);
+}
+
+int16_t eth_phy_rtl8211_get_link_status(uint32_t phy_addr) {
+ // Get the link mode & speed
+ eth_phy_write(phy_addr, PHY_RTL8211_PAGSR_ADDR, PHY_RTL8211_PHYSR_PAGE);
+ int16_t physr = eth_phy_read(phy_addr, PHY_RTL8211_PHYSR_ADDR);
+ eth_phy_write(phy_addr, PHY_RTL8211_PAGSR_ADDR, PHY_RTL8211_DEFAULT_PAGE);
+ int16_t status = 0;
+ switch ((physr & PHY_RTL8211_PHYSR_SPEED_Msk) >> PHY_RTL8211_PHYSR_SPEED_Pos) {
+ case 0:
+ status |= PHY_SPEED_10HALF;
+ break;
+ case 1:
+ status |= PHY_SPEED_100HALF;
+ break;
+ case 2:
+ status |= PHY_SPEED_1000HALF;
+ break;
+ }
+ if (physr & PHY_RTL8211_PHYSR_DUPLEX_Msk) {
+ status |= PHY_DUPLEX;
+ }
+ return status;
+}
+
#endif
diff --git a/ports/stm32/eth_phy.h b/ports/stm32/eth_phy.h
index dccfb7951..7d4bf4c46 100644
--- a/ports/stm32/eth_phy.h
+++ b/ports/stm32/eth_phy.h
@@ -50,17 +50,22 @@
#define PHY_ANAR_SPEED_100FULL (0x0100)
#define PHY_ANAR_IEEE802_3 (0x0001)
-#define PHY_SPEED_10HALF (1)
-#define PHY_SPEED_10FULL (5)
-#define PHY_SPEED_100HALF (2)
-#define PHY_SPEED_100FULL (6)
-#define PHY_DUPLEX (4)
+#define PHY_SPEED_10HALF (0x01)
+#define PHY_SPEED_100HALF (0x02)
+#define PHY_SPEED_1000HALF (0x04)
+#define PHY_DUPLEX (0x08)
+#define PHY_SPEED_10FULL (PHY_DUPLEX | PHY_SPEED_10HALF)
+#define PHY_SPEED_100FULL (PHY_DUPLEX | PHY_SPEED_100HALF)
+#define PHY_SPEED_1000FULL (PHY_DUPLEX | PHY_SPEED_1000HALF)
uint32_t eth_phy_read(uint32_t phy_addr, uint32_t reg);
void eth_phy_write(uint32_t phy_addr, uint32_t reg, uint32_t val);
+void eth_phy_generic_init(uint32_t phy_addr);
int16_t eth_phy_lan87xx_get_link_status(uint32_t phy_addr);
int16_t eth_phy_dp838xx_get_link_status(uint32_t phy_addr);
+void eth_phy_rtl8211_init(uint32_t phy_addr);
+int16_t eth_phy_rtl8211_get_link_status(uint32_t phy_addr);
#endif
diff --git a/ports/stm32/lwip_inc/lwipopts.h b/ports/stm32/lwip_inc/lwipopts.h
index ad1143845..5711ba894 100644
--- a/ports/stm32/lwip_inc/lwipopts.h
+++ b/ports/stm32/lwip_inc/lwipopts.h
@@ -1,6 +1,8 @@
#ifndef MICROPY_INCLUDED_STM32_LWIP_LWIPOPTS_H
#define MICROPY_INCLUDED_STM32_LWIP_LWIPOPTS_H
+#include STM32_HAL_H
+
#define LWIP_NETIF_EXT_STATUS_CALLBACK 1
#define LWIP_LOOPIF_MULTICAST 1
@@ -12,11 +14,12 @@
// Increase memory for lwIP to get better performance.
#if defined(STM32N6)
-#define MEM_SIZE (16 * 1024)
+#define MEM_SIZE (64 * 1024)
+#define PBUF_POOL_SIZE (32)
#define TCP_MSS (1460)
-#define TCP_WND (8 * TCP_MSS)
-#define TCP_SND_BUF (8 * TCP_MSS)
-#define MEMP_NUM_TCP_SEG (32)
+#define TCP_WND (16 * TCP_MSS)
+#define TCP_SND_BUF (16 * TCP_MSS)
+#define MEMP_NUM_TCP_SEG (64)
#endif
// Include common lwIP configuration.
diff --git a/ports/stm32/main.c b/ports/stm32/main.c
index 2d97adb1d..6f7413694 100644
--- a/ports/stm32/main.c
+++ b/ports/stm32/main.c
@@ -318,11 +318,14 @@ static void risaf_init(void) {
rimc_master.MasterCID = RIF_CID_1;
rimc_master.SecPriv = RIF_ATTRIBUTE_SEC | RIF_ATTRIBUTE_PRIV;
- HAL_RIF_RISC_SetSlaveSecureAttributes(RIF_RISC_PERIPH_INDEX_ADC12, RIF_ATTRIBUTE_SEC | RIF_ATTRIBUTE_PRIV);
HAL_RIF_RIMC_ConfigMasterAttributes(RIF_MASTER_INDEX_SDMMC1, &rimc_master);
- HAL_RIF_RISC_SetSlaveSecureAttributes(RIF_RISC_PERIPH_INDEX_SDMMC1, RIF_ATTRIBUTE_SEC | RIF_ATTRIBUTE_PRIV);
HAL_RIF_RIMC_ConfigMasterAttributes(RIF_MASTER_INDEX_SDMMC2, &rimc_master);
+ HAL_RIF_RIMC_ConfigMasterAttributes(RIF_MASTER_INDEX_ETH1, &rimc_master);
+
+ HAL_RIF_RISC_SetSlaveSecureAttributes(RIF_RISC_PERIPH_INDEX_ADC12, RIF_ATTRIBUTE_SEC | RIF_ATTRIBUTE_PRIV);
+ HAL_RIF_RISC_SetSlaveSecureAttributes(RIF_RISC_PERIPH_INDEX_SDMMC1, RIF_ATTRIBUTE_SEC | RIF_ATTRIBUTE_PRIV);
HAL_RIF_RISC_SetSlaveSecureAttributes(RIF_RISC_PERIPH_INDEX_SDMMC2, RIF_ATTRIBUTE_SEC | RIF_ATTRIBUTE_PRIV);
+ HAL_RIF_RISC_SetSlaveSecureAttributes(RIF_RISC_PERIPH_INDEX_ETH1, RIF_ATTRIBUTE_SEC | RIF_ATTRIBUTE_PRIV);
}
#endif
diff --git a/ports/stm32/network_lan.c b/ports/stm32/network_lan.c
index 0ef33e297..ea03329ad 100644
--- a/ports/stm32/network_lan.c
+++ b/ports/stm32/network_lan.c
@@ -33,6 +33,11 @@
#include "lwip/netif.h"
+// A board can customize the default PHY by defining this setting.
+#ifndef NETWORK_LAN_PHY
+#define NETWORK_LAN_PHY ETH_PHY_LAN8742
+#endif
+
typedef struct _network_lan_obj_t {
mp_obj_base_t base;
eth_t *eth;
@@ -57,7 +62,7 @@ static mp_obj_t network_lan_make_new(const mp_obj_type_t *type, size_t n_args, s
enum { ARG_phy_addr, ARG_phy_type};
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_phy_addr, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
- { MP_QSTR_phy_type, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = ETH_PHY_LAN8742} },
+ { MP_QSTR_phy_type, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NETWORK_LAN_PHY} },
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
diff --git a/ports/stm32/powerctrlboot.c b/ports/stm32/powerctrlboot.c
index a8ef8c34a..7baaa6773 100644
--- a/ports/stm32/powerctrlboot.c
+++ b/ports/stm32/powerctrlboot.c
@@ -482,6 +482,11 @@ void SystemClock_Config(void) {
LL_RCC_IC11_SetDivider(1);
LL_RCC_IC11_Enable();
+ // Configure IC12 at 100MHz for ETH1CLKSEL.
+ LL_RCC_IC12_SetSource(LL_RCC_ICCLKSOURCE_PLL1);
+ LL_RCC_IC12_SetDivider(8);
+ LL_RCC_IC12_Enable();
+
// Configure IC14 at 100MHz for slower peripherals.
LL_RCC_IC14_SetSource(LL_RCC_ICCLKSOURCE_PLL1);
LL_RCC_IC14_SetDivider(8);
diff --git a/ports/unix/Makefile b/ports/unix/Makefile
index 81751bf0f..70e4f3391 100644
--- a/ports/unix/Makefile
+++ b/ports/unix/Makefile
@@ -220,6 +220,7 @@ SRC_C += \
SHARED_SRC_C += $(addprefix shared/,\
runtime/gchelper_generic.c \
+ runtime/pyexec.c \
timeutils/timeutils.c \
$(SHARED_SRC_C_EXTRA) \
)
diff --git a/ports/unix/main.c b/ports/unix/main.c
index db50e12f5..ecc692449 100644
--- a/ports/unix/main.c
+++ b/ports/unix/main.c
@@ -55,9 +55,10 @@
#include "genhdr/mpversion.h"
#include "input.h"
#include "stack_size.h"
+#include "shared/runtime/pyexec.h"
// Command line options, with their defaults
-static bool compile_only = false;
+bool mp_compile_only = false;
static uint emit_opt = MP_EMIT_OPT_NONE;
#if MICROPY_ENABLE_GC
@@ -110,8 +111,6 @@ static int handle_uncaught_exception(mp_obj_base_t *exc) {
}
#define LEX_SRC_STR (1)
-#define LEX_SRC_VSTR (2)
-#define LEX_SRC_FILENAME (3)
#define LEX_SRC_STDIN (4)
// Returns standard error codes: 0 for success, 1 for all other errors,
@@ -127,12 +126,6 @@ static int execute_from_lexer(int source_kind, const void *source, mp_parse_inpu
if (source_kind == LEX_SRC_STR) {
const char *line = source;
lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, line, strlen(line), false);
- } else if (source_kind == LEX_SRC_VSTR) {
- const vstr_t *vstr = source;
- lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr->buf, vstr->len, false);
- } else if (source_kind == LEX_SRC_FILENAME) {
- const char *filename = (const char *)source;
- lex = mp_lexer_new_from_file(qstr_from_str(filename));
} else { // LEX_SRC_STDIN
lex = mp_lexer_new_from_fd(MP_QSTR__lt_stdin_gt_, 0, false);
}
@@ -158,7 +151,7 @@ static int execute_from_lexer(int source_kind, const void *source, mp_parse_inpu
mp_obj_t module_fun = mp_compile(&parse_tree, source_name, is_repl);
- if (!compile_only) {
+ if (!mp_compile_only) {
// execute it
mp_call_function_0(module_fun);
}
@@ -195,95 +188,32 @@ static char *strjoin(const char *s1, int sep_char, const char *s2) {
#endif
static int do_repl(void) {
- mp_hal_stdout_tx_str(MICROPY_BANNER_NAME_AND_VERSION);
- mp_hal_stdout_tx_str("; " MICROPY_BANNER_MACHINE);
- mp_hal_stdout_tx_str("\nUse Ctrl-D to exit, Ctrl-E for paste mode\n");
-
#if MICROPY_USE_READLINE == 1
- // use MicroPython supplied readline
+ // use MicroPython supplied readline-based REPL
- vstr_t line;
- vstr_init(&line, 16);
+ int ret = 0;
for (;;) {
- mp_hal_stdio_mode_raw();
-
- input_restart:
- // If the GC is locked at this point there is no way out except a reset,
- // so force the GC to be unlocked to help the user debug what went wrong.
- MP_STATE_THREAD(gc_lock_depth) = 0;
- vstr_reset(&line);
- int ret = readline(&line, mp_repl_get_ps1());
- mp_parse_input_kind_t parse_input_kind = MP_PARSE_SINGLE_INPUT;
-
- if (ret == CHAR_CTRL_C) {
- // cancel input
- mp_hal_stdout_tx_str("\r\n");
- goto input_restart;
- } else if (ret == CHAR_CTRL_D) {
- // EOF
- printf("\n");
- mp_hal_stdio_mode_orig();
- vstr_clear(&line);
- return 0;
- } else if (ret == CHAR_CTRL_E) {
- // paste mode
- mp_hal_stdout_tx_str("\npaste mode; Ctrl-C to cancel, Ctrl-D to finish\n=== ");
- vstr_reset(&line);
- for (;;) {
- char c = mp_hal_stdin_rx_chr();
- if (c == CHAR_CTRL_C) {
- // cancel everything
- mp_hal_stdout_tx_str("\n");
- goto input_restart;
- } else if (c == CHAR_CTRL_D) {
- // end of input
- mp_hal_stdout_tx_str("\n");
- break;
- } else {
- // add char to buffer and echo
- vstr_add_byte(&line, c);
- if (c == '\r') {
- mp_hal_stdout_tx_str("\n=== ");
- } else {
- mp_hal_stdout_tx_strn(&c, 1);
- }
- }
- }
- parse_input_kind = MP_PARSE_FILE_INPUT;
- } else if (line.len == 0) {
- if (ret != 0) {
- printf("\n");
+ if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
+ if ((ret = pyexec_raw_repl()) != 0) {
+ break;
}
- goto input_restart;
} else {
- // got a line with non-zero length, see if it needs continuing
- while (mp_repl_continue_with_input(vstr_null_terminated_str(&line))) {
- vstr_add_byte(&line, '\n');
- ret = readline(&line, mp_repl_get_ps2());
- if (ret == CHAR_CTRL_C) {
- // cancel everything
- printf("\n");
- goto input_restart;
- } else if (ret == CHAR_CTRL_D) {
- // stop entering compound statement
- break;
- }
+ if ((ret = pyexec_friendly_repl()) != 0) {
+ break;
}
}
-
- mp_hal_stdio_mode_orig();
-
- ret = execute_from_lexer(LEX_SRC_VSTR, &line, parse_input_kind, true);
- if (ret & FORCED_EXIT) {
- return ret;
- }
}
+ return ret;
#else
// use simple readline
+ mp_hal_stdout_tx_str(MICROPY_BANNER_NAME_AND_VERSION);
+ mp_hal_stdout_tx_str("; " MICROPY_BANNER_MACHINE);
+ mp_hal_stdout_tx_str("\nUse Ctrl-D to exit, Ctrl-E for paste mode\n");
+
for (;;) {
char *line = prompt((char *)mp_repl_get_ps1());
if (line == NULL) {
@@ -311,12 +241,40 @@ static int do_repl(void) {
#endif
}
+static inline int convert_pyexec_result(int ret) {
+ #if MICROPY_PYEXEC_ENABLE_EXIT_CODE_HANDLING
+ // With exit code handling enabled:
+ // pyexec returns exit code with PYEXEC_FORCED_EXIT flag set for SystemExit
+ // Unix port expects: 0 for success, non-zero for error/exit
+ if (ret & PYEXEC_FORCED_EXIT) {
+ // SystemExit: extract exit code from lower bits
+ return ret & 0xFF;
+ }
+ // Normal execution or exception: return as-is (0 for success, 1 for exception)
+ return ret;
+ #else
+ // pyexec returns 1 for success, 0 for exception, PYEXEC_FORCED_EXIT for SystemExit
+ // Convert to unix port's expected codes: 0 for success, 1 for exception, FORCED_EXIT|val for SystemExit
+ if (ret == 1) {
+ return 0; // success
+ } else if (ret & PYEXEC_FORCED_EXIT) {
+ return ret; // SystemExit with exit value in lower 8 bits
+ } else {
+ return 1; // exception
+ }
+ #endif
+}
+
static int do_file(const char *file) {
- return execute_from_lexer(LEX_SRC_FILENAME, file, MP_PARSE_FILE_INPUT, false);
+ return convert_pyexec_result(pyexec_file(file));
}
static int do_str(const char *str) {
- return execute_from_lexer(LEX_SRC_STR, str, MP_PARSE_FILE_INPUT, false);
+ vstr_t vstr;
+ vstr.buf = (char *)str;
+ vstr.len = strlen(str);
+ int ret = pyexec_vstr(&vstr, true);
+ return convert_pyexec_result(ret);
}
static void print_help(char **argv) {
@@ -385,7 +343,7 @@ static void pre_process_options(int argc, char **argv) {
}
if (0) {
} else if (strcmp(argv[a + 1], "compile-only") == 0) {
- compile_only = true;
+ mp_compile_only = true;
} else if (strcmp(argv[a + 1], "emit=bytecode") == 0) {
emit_opt = MP_EMIT_OPT_BYTECODE;
#if MICROPY_EMIT_NATIVE
diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h
index f07439863..854da1dbd 100644
--- a/ports/unix/mpconfigport.h
+++ b/ports/unix/mpconfigport.h
@@ -151,6 +151,12 @@ typedef long mp_off_t;
// Enable sys.executable.
#define MICROPY_PY_SYS_EXECUTABLE (1)
+// Enable support for compile-only mode.
+#define MICROPY_PYEXEC_COMPILE_ONLY (1)
+
+// Enable handling of sys.exit() exit codes.
+#define MICROPY_PYEXEC_ENABLE_EXIT_CODE_HANDLING (1)
+
#define MICROPY_PY_SOCKET_LISTEN_BACKLOG_DEFAULT (SOMAXCONN < 128 ? SOMAXCONN : 128)
// Bare-metal ports don't have stderr. Printing debug to stderr may give tests
diff --git a/ports/unix/mphalport.h b/ports/unix/mphalport.h
index 0efd6940b..97c24978a 100644
--- a/ports/unix/mphalport.h
+++ b/ports/unix/mphalport.h
@@ -25,6 +25,7 @@
*/
#include <errno.h>
#include <unistd.h>
+#include <stdbool.h>
#ifndef CHAR_CTRL_C
#define CHAR_CTRL_C (3)
@@ -47,6 +48,9 @@
MP_THREAD_GIL_ENTER(); \
} while (0)
+// The port provides `mp_hal_stdio_mode_raw()` and `mp_hal_stdio_mode_orig()`.
+#define MICROPY_HAL_HAS_STDIO_MODE_SWITCH (1)
+
void mp_hal_set_interrupt_char(char c);
#define mp_hal_stdio_poll unused // this is not implemented, nor needed
@@ -117,3 +121,6 @@ enum {
void mp_hal_get_mac(int idx, uint8_t buf[6]);
#endif
+
+// Global variable to control compile-only mode.
+extern bool mp_compile_only;
diff --git a/ports/windows/Makefile b/ports/windows/Makefile
index 9eee98cdd..4129b7fe2 100644
--- a/ports/windows/Makefile
+++ b/ports/windows/Makefile
@@ -83,6 +83,7 @@ OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o))
ifeq ($(MICROPY_USE_READLINE),1)
CFLAGS += -DMICROPY_USE_READLINE=1
SRC_C += shared/readline/readline.c
+SRC_C += shared/runtime/pyexec.c
endif
LIB += -lws2_32
diff --git a/ports/windows/micropython.vcxproj b/ports/windows/micropython.vcxproj
index 9326f3f4c..f8bbec82c 100644
--- a/ports/windows/micropython.vcxproj
+++ b/ports/windows/micropython.vcxproj
@@ -89,6 +89,7 @@
<ClCompile Include="@(PyExtModSource)" />
<ClCompile Include="$(PyBaseDir)shared\readline\*.c" />
<ClCompile Include="$(PyBaseDir)shared\runtime\gchelper_generic.c" />
+ <ClCompile Include="$(PyBaseDir)shared\runtime\pyexec.c" />
<ClCompile Include="$(PyBaseDir)ports\windows\*.c" />
<ClCompile Include="$(PyBaseDir)ports\windows\msvc\*.c" />
<ClCompile Include="$(PyBaseDir)ports\unix\gccollect.c"/>
diff --git a/ports/windows/mpconfigport.h b/ports/windows/mpconfigport.h
index 68744ba93..1edcd0ede 100644
--- a/ports/windows/mpconfigport.h
+++ b/ports/windows/mpconfigport.h
@@ -161,6 +161,12 @@
#define MICROPY_MACHINE_MEM_GET_READ_ADDR mod_machine_mem_get_addr
#define MICROPY_MACHINE_MEM_GET_WRITE_ADDR mod_machine_mem_get_addr
+// Enable support for compile-only mode.
+#define MICROPY_PYEXEC_COMPILE_ONLY (1)
+
+// Enable handling of sys.exit() exit codes.
+#define MICROPY_PYEXEC_ENABLE_EXIT_CODE_HANDLING (1)
+
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_DETAILED)
#define MICROPY_ERROR_PRINTER (&mp_stderr_print)
#define MICROPY_WARNINGS (1)
diff --git a/ports/zephyr/CMakeLists.txt b/ports/zephyr/CMakeLists.txt
index e7a55d804..9db0a95c6 100644
--- a/ports/zephyr/CMakeLists.txt
+++ b/ports/zephyr/CMakeLists.txt
@@ -55,6 +55,7 @@ set(MICROPY_SOURCE_PORT
uart_core.c
zephyr_device.c
zephyr_storage.c
+ zephyr_filesystem.c
mpthreadport.c
)
list(TRANSFORM MICROPY_SOURCE_PORT PREPEND ${MICROPY_PORT_DIR}/)
@@ -81,14 +82,33 @@ set(MICROPY_QSTRDEFS_PORT
${MICROPY_PORT_DIR}/qstrdefsport.h
)
-set(MICROPY_SOURCE_LIB
+if (CONFIG_MICROPY_VFS_FAT)
+
+list(APPEND MICROPY_SOURCE_LIB
oofatfs/ff.c
oofatfs/ffunicode.c
+)
+
+endif()
+
+if (CONFIG_MICROPY_VFS_LFS1)
+
+list(APPEND MICROPY_SOURCE_LIB
littlefs/lfs1.c
littlefs/lfs1_util.c
+)
+
+endif()
+
+if (CONFIG_MICROPY_VFS_LFS2)
+
+list(APPEND MICROPY_SOURCE_LIB
littlefs/lfs2.c
littlefs/lfs2_util.c
)
+
+endif()
+
list(TRANSFORM MICROPY_SOURCE_LIB PREPEND ${MICROPY_DIR}/lib/)
set(MICROPY_SOURCE_QSTR
diff --git a/ports/zephyr/README.md b/ports/zephyr/README.md
index eedcdcb58..f3fcd8f70 100644
--- a/ports/zephyr/README.md
+++ b/ports/zephyr/README.md
@@ -208,3 +208,47 @@ run the following after you built an image with the previous command:
$ west build -t run
+File Systems
+------------
+
+The Zephyr Micropython port provides 2 options for handling filesystems on the device:
+The first is the Micropython filesystem management, which uses Micropython's filesystem code and
+relies on zephyr's FlashArea API, this is enabled by default when
+`CONFIG_FLASH` and `CONFIG_FLASH_MAP` are turned on.
+The second option is using Zephyr's Filesystem management:
+This relies on Zephyr's File System features and enables sharing access between zephyr and
+micropython code. Several configuration options must be enabled:
+
+ CONFIG_FLASH_MAP=y # Requirement for the file system subsystem
+ CONFIG_FILE_SYSTEM=y # Enables the file system subsystem
+ CONFIG_FILE_SYSTEM_LITTLEFS=y # Enables the littlefs support in zephyr
+ CONFIG_FILE_SYSTEM_MKFS=y # Enables the ability to create new file systems
+
+Then, a fstab must be added to the dts overlay, for example:
+
+
+ fstab {
+ compatible = "zephyr,fstab";
+ lfs2: lfs2 {
+ compatible = "zephyr,fstab,littlefs";
+ mount-point = "/flash";
+ partition = <&storage_partition>;
+ read-size=<16>;
+ prog-size=<4096>;
+ cache-size=<4096>;
+ lookahead-size=<32>;
+ block-cycles=<4>;
+ };
+ };
+
+It is then possible to use the FS like a normal Micropython filesystem:
+
+ import vfs, zephyr
+ zfs = zephyr.FileSystem(zephyr.FileSystem.fstab()[0])
+ vfs.mount(zfs, "/zephyr")
+
+You may disable Micropython's File system code to save space:
+
+ CONFIG_MICROPY_VFS_FAT=n
+ CONFIG_MICROPY_VFS_LFS1=n
+ CONFIG_MICROPY_VFS_LFS2=n
diff --git a/ports/zephyr/boards/rpi_pico.conf b/ports/zephyr/boards/rpi_pico.conf
index 683279ddc..6a0be1c37 100644
--- a/ports/zephyr/boards/rpi_pico.conf
+++ b/ports/zephyr/boards/rpi_pico.conf
@@ -18,3 +18,13 @@ CONFIG_SPI=y
# MicroPython config.
CONFIG_MICROPY_HEAP_SIZE=196608
+
+# File System Configuration
+CONFIG_FILE_SYSTEM=y
+CONFIG_FILE_SYSTEM_LITTLEFS=y
+CONFIG_FILE_SYSTEM_MKFS=y
+CONFIG_MICROPY_VFS_FAT=n
+CONFIG_MICROPY_VFS_LFS1=n
+CONFIG_MICROPY_VFS_LFS2=n
+# Default heap for littlefs is too small
+CONFIG_FS_LITTLEFS_FC_HEAP_SIZE=8192
diff --git a/ports/zephyr/boards/rpi_pico.overlay b/ports/zephyr/boards/rpi_pico.overlay
index d63ed73bd..436e4210a 100644
--- a/ports/zephyr/boards/rpi_pico.overlay
+++ b/ports/zephyr/boards/rpi_pico.overlay
@@ -9,6 +9,20 @@
/* Use USB CDC ACM as the console. */
zephyr,console = &cdc_acm_uart0;
};
+
+ fstab {
+ compatible = "zephyr,fstab";
+ lfs: lfs {
+ compatible = "zephyr,fstab,littlefs";
+ mount-point = "/flash";
+ partition = <&storage_partition>;
+ read-size=<16>;
+ prog-size=<256>;
+ cache-size=<1024>;
+ lookahead-size=<32>;
+ block-cycles=<4>;
+ };
+ };
};
/* Delete defined partitions and make a layout matching the rp2 port RPI_PICO configuration. */
diff --git a/ports/zephyr/modules/_boot.py b/ports/zephyr/modules/_boot.py
index d0ba21d3f..ab3ed9c63 100644
--- a/ports/zephyr/modules/_boot.py
+++ b/ports/zephyr/modules/_boot.py
@@ -11,12 +11,39 @@ FlashArea = getattr(zephyr, "FlashArea", None)
# DiskAccess depends on CONFIG_DISK_ACCESS
DiskAccess = getattr(zephyr, "DiskAccess", None)
+# zephyr.FileSystem depends on CONFIG_FILE_SYSTEM and CONFIG_FLASH_MAP
+FileSystem = getattr(zephyr, "FileSystem", None)
+
_FLASH = const("/flash")
_FLASH_LIB = const("/flash/lib")
_STORAGE_KEY = const("storage")
_FLASH_EXISTS = False
+def mount_filesystem_flash():
+ """Create a filesystem if needed on the FS partition "/flash"
+ and mount it on /flash.
+ Return True if successful, False otherwise.
+ """
+ if _FLASH in FileSystem.fstab():
+ fs = FileSystem(_FLASH)
+ retval = True
+ try:
+ vfs.mount(fs, _FLASH)
+ except OSError:
+ if getattr(fs, "mkfs", None):
+ try:
+ fs.mkfs()
+ vfs.mount(fs, _FLASH)
+ except OSError:
+ print("Error formatting flash partition")
+ retval = False
+ else:
+ retval = False
+ return retval
+ return False
+
+
def create_flash_partition():
"""Create an LFS2 filesystem on the partition labeled storage
and mount it on /flash.
@@ -54,7 +81,10 @@ def mount_all_disks():
return retval
-if FlashArea and create_flash_partition():
+# Prefer FileSystem over FlashArea Access
+if FileSystem and mount_filesystem_flash():
+ _FLASH_EXISTS = True
+elif FlashArea and create_flash_partition():
_FLASH_EXISTS = True
# Prefer disks to /flash
@@ -67,6 +97,6 @@ if _FLASH_EXISTS:
sys.path.append(_FLASH_LIB)
# Cleanup globals for boot.py/main.py
-del FlashArea, DiskAccess, zephyr
+del FlashArea, DiskAccess, FileSystem, zephyr
del sys, vfs, os, const
-del create_flash_partition, mount_all_disks, _FLASH_EXISTS
+del mount_filesystem_flash, create_flash_partition, mount_all_disks, _FLASH_EXISTS
diff --git a/ports/zephyr/modzephyr.c b/ports/zephyr/modzephyr.c
index 08fdf5c5a..7726737e1 100644
--- a/ports/zephyr/modzephyr.c
+++ b/ports/zephyr/modzephyr.c
@@ -86,6 +86,9 @@ static const mp_rom_map_elem_t mp_module_time_globals_table[] = {
#ifdef CONFIG_FLASH_MAP
{ MP_ROM_QSTR(MP_QSTR_FlashArea), MP_ROM_PTR(&zephyr_flash_area_type) },
#endif
+ #ifdef CONFIG_FILE_SYSTEM
+ { MP_ROM_QSTR(MP_QSTR_FileSystem), MP_ROM_PTR(&zephyr_filesystem_type) },
+ #endif
};
static MP_DEFINE_CONST_DICT(mp_module_time_globals, mp_module_time_globals_table);
diff --git a/ports/zephyr/modzephyr.h b/ports/zephyr/modzephyr.h
index f9b7e8eea..834ec4a31 100644
--- a/ports/zephyr/modzephyr.h
+++ b/ports/zephyr/modzephyr.h
@@ -37,4 +37,8 @@ extern const mp_obj_type_t zephyr_disk_access_type;
extern const mp_obj_type_t zephyr_flash_area_type;
#endif
+#ifdef CONFIG_FILE_SYSTEM
+extern const mp_obj_type_t zephyr_filesystem_type;
+#endif
+
#endif // MICROPY_INCLUDED_ZEPHYR_MODZEPHYR_H
diff --git a/ports/zephyr/mpconfigport.h b/ports/zephyr/mpconfigport.h
index 8d5d60ed2..7f8497348 100644
--- a/ports/zephyr/mpconfigport.h
+++ b/ports/zephyr/mpconfigport.h
@@ -84,9 +84,10 @@
#endif
#define MICROPY_PY_MACHINE_PWM (1)
#define MICROPY_PY_MACHINE_PWM_INCLUDEFILE "ports/zephyr/machine_pwm.c"
-#ifdef CONFIG_NETWORKING
-// If we have networking, we likely want errno comfort
+#if defined(CONFIG_NETWORKING) || defined(CONFIG_FILE_SYSTEM)
#define MICROPY_PY_ERRNO (1)
+#endif
+#ifdef CONFIG_NETWORKING
#define MICROPY_PY_SOCKET (1)
#endif
#ifdef CONFIG_BT
diff --git a/ports/zephyr/zephyr_filesystem.c b/ports/zephyr/zephyr_filesystem.c
new file mode 100644
index 000000000..2ca726253
--- /dev/null
+++ b/ports/zephyr/zephyr_filesystem.c
@@ -0,0 +1,782 @@
+/*
+* This file is part of the MicroPython project, http://micropython.org/
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2025 MASSDRIVER EI (massdriver.space)
+*
+* 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/mpconfig.h"
+
+#if CONFIG_FILE_SYSTEM
+
+#if !MICROPY_VFS
+#error "with CONFIG_FILE_SYSTEM enabled, must also enable MICROPY_VFS"
+#endif
+
+#include <zephyr/fs/fs.h>
+#include <zephyr/fs/fs_sys.h>
+
+#include <string.h>
+#include "py/obj.h"
+#include "py/objstr.h"
+#include "py/runtime.h"
+#include "py/stream.h"
+#include "py/mperrno.h"
+#include "extmod/vfs.h"
+#include "shared/timeutils/timeutils.h"
+
+// Declare each FSTAB entry
+#define FOREACH_FS_DEFINE(fs) FS_FSTAB_DECLARE_ENTRY(fs);
+
+#define FOREACH_FSTAB_DEFINE(n) DT_FOREACH_CHILD(n, FOREACH_FS_DEFINE)
+
+DT_FOREACH_STATUS_OKAY(zephyr_fstab, FOREACH_FSTAB_DEFINE)
+
+// Add all FSTAB entries to a table for us to use dynamically
+#define FOREACH_FS(fs) FS_FSTAB_ENTRY(fs)
+
+#define FOREACH_FSTAB(n) DT_FOREACH_CHILD(n, FOREACH_FS)
+
+static struct fs_mount_t *const zephyr_fs_mounts[] = {
+ &DT_FOREACH_STATUS_OKAY(zephyr_fstab, FOREACH_FSTAB),
+};
+
+#define zephyr_fs_mounts_size sizeof(zephyr_fs_mounts) / sizeof(struct fs_mount_t *)
+
+typedef struct _zephyr_fs_obj_t {
+ mp_obj_base_t base;
+ struct fs_mount_t *mount;
+ vstr_t cur_dir;
+ vstr_t root_dir;
+} zephyr_fs_obj_t;
+
+const char *zephyr_fs_make_path(zephyr_fs_obj_t *self, mp_obj_t path_in) {
+ const char *path = mp_obj_str_get_str(path_in);
+
+ if (path[0] != '/') {
+ size_t l = vstr_len(&self->root_dir);
+ size_t lc = vstr_len(&self->cur_dir);
+ vstr_add_str(&self->root_dir, "/");
+ vstr_add_strn(&self->root_dir, self->cur_dir.buf, lc);
+ vstr_add_str(&self->root_dir, path);
+ path = vstr_null_terminated_str(&self->root_dir);
+ self->root_dir.len = l;
+ } else {
+ size_t l = vstr_len(&self->root_dir);
+ vstr_add_str(&self->root_dir, path);
+ path = vstr_null_terminated_str(&self->root_dir);
+ self->root_dir.len = l;
+ }
+ return path;
+}
+
+typedef struct _zephyr_file_obj_t {
+ mp_obj_base_t base;
+ struct fs_file_t fp;
+} zephyr_file_obj_t;
+
+static void file_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ (void)kind;
+ mp_printf(print, "<io.%s %p>", mp_obj_get_type_str(self_in), MP_OBJ_TO_PTR(self_in));
+}
+
+static mp_uint_t file_obj_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
+ zephyr_file_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ ssize_t err;
+
+ err = fs_read(&self->fp, buf, size);
+ if (err < 0) {
+ *errcode = -err;
+ return MP_STREAM_ERROR;
+ }
+ return err;
+}
+
+static mp_uint_t file_obj_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
+ zephyr_file_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ ssize_t err;
+
+ err = fs_write(&self->fp, buf, size);
+ if (err < 0) {
+ *errcode = -err;
+ return MP_STREAM_ERROR;
+ }
+ return err;
+}
+
+static mp_uint_t file_obj_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {
+ zephyr_file_obj_t *self = MP_OBJ_TO_PTR(o_in);
+ int err = -EINVAL;
+
+ if (request == MP_STREAM_SEEK) {
+ struct mp_stream_seek_t *s = (struct mp_stream_seek_t *)(uintptr_t)arg;
+
+ MP_STATIC_ASSERT(FS_SEEK_SET == MP_SEEK_SET);
+ MP_STATIC_ASSERT(FS_SEEK_CUR == MP_SEEK_CUR);
+ MP_STATIC_ASSERT(FS_SEEK_END == MP_SEEK_END);
+
+ err = fs_seek(&self->fp, s->offset, s->whence);
+
+ if (err < 0) {
+ *errcode = -err;
+ return MP_STREAM_ERROR;
+ }
+
+ off_t tell = fs_tell(&self->fp);
+ if (tell < 0) {
+ *errcode = -err;
+ return MP_STREAM_ERROR;
+ }
+ s->offset = tell;
+ return 0;
+
+ } else if (request == MP_STREAM_FLUSH) {
+ err = fs_sync(&self->fp);
+ if (err < 0) {
+ *errcode = -err;
+ return MP_STREAM_ERROR;
+ }
+ return 0;
+
+ } else if (request == MP_STREAM_CLOSE) {
+ err = fs_close(&self->fp);
+ if (err < 0) {
+ *errcode = -err;
+ return MP_STREAM_ERROR;
+ }
+ return 0;
+
+ } else {
+ *errcode = MP_EINVAL;
+ return MP_STREAM_ERROR;
+ }
+}
+
+static const mp_rom_map_elem_t zephyr_fs_rawfile_locals_dict_table[] = {
+ { 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_readlines), MP_ROM_PTR(&mp_stream_unbuffered_readlines_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
+ { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) },
+ { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) },
+ { MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) },
+ { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&mp_stream___exit___obj) },
+};
+
+static MP_DEFINE_CONST_DICT(zephyr_fs_rawfile_locals_dict, zephyr_fs_rawfile_locals_dict_table);
+
+static const mp_stream_p_t zephyr_fs_fileio_stream_p = {
+ .read = file_obj_read,
+ .write = file_obj_write,
+ .ioctl = file_obj_ioctl,
+};
+
+MP_DEFINE_CONST_OBJ_TYPE(
+ mp_type_zephyr_fs_fileio,
+ MP_QSTR_FileIO,
+ MP_TYPE_FLAG_ITER_IS_STREAM,
+ print, file_obj_print,
+ protocol, &zephyr_fs_fileio_stream_p,
+ locals_dict, &zephyr_fs_rawfile_locals_dict
+ );
+
+static const mp_stream_p_t zephyr_fs_textio_stream_p = {
+ .read = file_obj_read,
+ .write = file_obj_write,
+ .ioctl = file_obj_ioctl,
+ .is_text = true,
+};
+
+MP_DEFINE_CONST_OBJ_TYPE(
+ mp_type_zephyr_fs_textio,
+ MP_QSTR_TextIOWrapper,
+ MP_TYPE_FLAG_ITER_IS_STREAM,
+ print, file_obj_print,
+ protocol, &zephyr_fs_textio_stream_p,
+ locals_dict, &zephyr_fs_rawfile_locals_dict
+ );
+
+// Factory function for I/O stream classes
+static mp_obj_t zephyr_fs_open(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode_in) {
+ zephyr_fs_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ const mp_obj_type_t *type = &mp_type_zephyr_fs_textio;
+ int flags = 0;
+ int err;
+ bool x_mode = false;
+ const char *mode_str = mp_obj_str_get_str(mode_in);
+ const char *path = zephyr_fs_make_path(self, path_in);
+
+ for (; *mode_str; ++mode_str) {
+ int new_flags = 0;
+ switch (*mode_str) {
+ case 'r':
+ new_flags = FS_O_READ;
+ break;
+ case 'w':
+ new_flags = FS_O_WRITE | FS_O_CREATE | FS_O_TRUNC;
+ break;
+ case 'x':
+ new_flags = FS_O_WRITE;
+ x_mode = true;
+ break;
+ case 'a':
+ new_flags = FS_O_WRITE | FS_O_CREATE | FS_O_APPEND;
+ break;
+ case '+':
+ flags |= FS_O_RDWR;
+ break;
+ case 'b':
+ type = &mp_type_zephyr_fs_fileio;
+ break;
+ case 't':
+ type = &mp_type_zephyr_fs_textio;
+ break;
+ }
+ if (new_flags) {
+ if (flags) {
+ mp_raise_ValueError(NULL);
+ }
+ flags = new_flags;
+ }
+ }
+
+ zephyr_file_obj_t *o = mp_obj_malloc_with_finaliser(zephyr_file_obj_t, type);
+
+ err = fs_open(&o->fp, path, flags);
+ if (x_mode && err < 0) {
+ err = fs_open(&o->fp, path, flags | FS_O_CREATE);
+ } else if (x_mode) {
+ fs_close(&o->fp);
+ mp_raise_msg_varg(&mp_type_OSError,
+ MP_ERROR_TEXT("file %s Already exists: %q"), path, mp_errno_to_str(MP_OBJ_NEW_SMALL_INT(-err)));
+ return mp_const_none;
+ }
+ if (err < 0) {
+ m_del_obj(zephyr_file_obj_t, o);
+ mp_raise_msg_varg(&mp_type_OSError,
+ MP_ERROR_TEXT("error opening file %s: %q"), path, mp_errno_to_str(MP_OBJ_NEW_SMALL_INT(-err)));
+ return mp_const_none;
+ }
+
+ return MP_OBJ_FROM_PTR(o);
+}
+MP_DEFINE_CONST_FUN_OBJ_3(zephyr_fs_open_obj, zephyr_fs_open);
+
+typedef struct _mp_zephyr_fs_ilistdir_it_t {
+ mp_obj_base_t base;
+ mp_fun_1_t iternext;
+ mp_fun_1_t finaliser;
+ bool is_str;
+ struct fs_dir_t dir;
+} mp_zephyr_fs_ilistdir_it_t;
+
+static mp_obj_t mp_zephyr_fs_ilistdir_it_iternext(mp_obj_t self_in) {
+ mp_zephyr_fs_ilistdir_it_t *self = MP_OBJ_TO_PTR(self_in);
+ int err;
+
+ for (;;) {
+ struct fs_dirent stats;
+ err = fs_readdir(&self->dir, &stats);
+ char *fn = stats.name;
+ if (err < 0 || stats.name[0] == 0) {
+ // stop on error or end of dir
+ break;
+ }
+
+ // Note that Zephyr FS also already filters . and .., so we don't need to
+
+ // make 4-tuple with info about this entry
+ mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(4, NULL));
+ if (self->is_str) {
+ t->items[0] = mp_obj_new_str_from_cstr(fn);
+ } else {
+ t->items[0] = mp_obj_new_bytes((const byte *)fn, strlen(fn));
+ }
+ if (stats.type == FS_DIR_ENTRY_DIR) {
+ // dir
+ t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR);
+ } else {
+ // file
+ t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFREG);
+ }
+ t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // no inode number
+ t->items[3] = mp_obj_new_int_from_uint(stats.size);
+
+ return MP_OBJ_FROM_PTR(t);
+ }
+
+ // ignore error because we may be closing a second time
+ fs_closedir(&self->dir);
+
+ return MP_OBJ_STOP_ITERATION;
+}
+
+static mp_obj_t mp_zephyr_fs_ilistdir_it_del(mp_obj_t self_in) {
+ mp_zephyr_fs_ilistdir_it_t *self = MP_OBJ_TO_PTR(self_in);
+ // ignore result / error because we may be closing a second time.
+ fs_closedir(&self->dir);
+ return mp_const_none;
+}
+
+static mp_obj_t zephyr_fs_ilistdir_func(size_t n_args, const mp_obj_t *args) {
+ zephyr_fs_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ bool is_str_type = true;
+ const char *path;
+ int err;
+
+ if (n_args == 2) {
+ if (mp_obj_get_type(args[1]) == &mp_type_bytes) {
+ is_str_type = false;
+ }
+ path = zephyr_fs_make_path(self, args[1]);
+ } else {
+ path = "";
+ }
+
+ // Create a new iterator object to list the dir
+ mp_zephyr_fs_ilistdir_it_t *iter = mp_obj_malloc_with_finaliser(mp_zephyr_fs_ilistdir_it_t, &mp_type_polymorph_iter_with_finaliser);
+ iter->iternext = mp_zephyr_fs_ilistdir_it_iternext;
+ iter->finaliser = mp_zephyr_fs_ilistdir_it_del;
+ iter->is_str = is_str_type;
+
+ err = fs_opendir(&iter->dir, path);
+ if (err < 0) {
+ mp_raise_msg_varg(&mp_type_OSError,
+ MP_ERROR_TEXT("could not open directory %s: %q"), path, mp_errno_to_str(MP_OBJ_NEW_SMALL_INT(-err)));
+ return mp_const_none;
+ }
+
+ return MP_OBJ_FROM_PTR(iter);
+}
+static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(zephyr_fs_ilistdir_obj, 1, 2, zephyr_fs_ilistdir_func);
+
+static mp_obj_t zephyr_fs_mkdir(mp_obj_t vfs_in, mp_obj_t path_o) {
+ zephyr_fs_obj_t *self = MP_OBJ_TO_PTR(vfs_in);
+ const char *path = zephyr_fs_make_path(self, path_o);
+ int err;
+
+ err = fs_mkdir(path);
+ if (err < 0) {
+ mp_raise_msg_varg(&mp_type_OSError,
+ MP_ERROR_TEXT("could not mkdir %s: %q"), path, mp_errno_to_str(MP_OBJ_NEW_SMALL_INT(-err)));
+ return mp_const_none;
+ }
+ return mp_const_none;
+}
+static MP_DEFINE_CONST_FUN_OBJ_2(zephyr_fs_mkdir_obj, zephyr_fs_mkdir);
+
+
+static mp_obj_t zephyr_fs_chdir(mp_obj_t vfs_in, mp_obj_t path_in) {
+ zephyr_fs_obj_t *self = MP_OBJ_TO_PTR(vfs_in);
+ const char *path = mp_obj_str_get_str(path_in);
+ size_t lc = vstr_len(&self->cur_dir);
+ size_t l = vstr_len(&self->root_dir);
+ vstr_t chdir;
+ struct fs_dirent stats;
+ int err;
+
+
+ vstr_init(&chdir, 32);
+ vstr_add_strn(&chdir, self->root_dir.buf, l);
+ if (path[0] != '/') {
+ vstr_add_byte(&chdir, '/');
+ vstr_add_strn(&chdir, self->cur_dir.buf, lc);
+ }
+ vstr_add_str(&chdir, path);
+ vstr_add_byte(&chdir, '/');
+
+ #define CWD_LEN (vstr_len(&chdir))
+ size_t to = 1;
+ size_t from = 1;
+ char *cwd = vstr_str(&chdir);
+ while (from < CWD_LEN) {
+ for (; from < CWD_LEN && cwd[from] == '/'; ++from) {
+ // Scan for the start
+ }
+ if (from > to) {
+ // Found excessive slash chars, squeeze them out
+ vstr_cut_out_bytes(&chdir, to, from - to);
+ from = to;
+ }
+ for (; from < CWD_LEN && cwd[from] != '/'; ++from) {
+ // Scan for the next /
+ }
+ if ((from - to) == 1 && cwd[to] == '.') {
+ // './', ignore
+ vstr_cut_out_bytes(&chdir, to, ++from - to);
+ from = to;
+ } else if ((from - to) == 2 && cwd[to] == '.' && cwd[to + 1] == '.') {
+ // '../', skip back
+ if (to > 1) {
+ // Only skip back if not at the tip
+ for (--to; to > 1 && cwd[to - 1] != '/'; --to) {
+ // Skip back
+ }
+ }
+ vstr_cut_out_bytes(&chdir, to, ++from - to);
+ from = to;
+ } else {
+ // Normal element, keep it and just move the offset
+ to = ++from;
+ }
+ }
+
+ err = fs_stat(vstr_null_terminated_str(&chdir), &stats);
+ vstr_cut_out_bytes(&chdir, 0, l + 1);
+ lc = vstr_len(&chdir);
+ if (err < 0) {
+ mp_raise_msg_varg(&mp_type_OSError,
+ MP_ERROR_TEXT("could not chdir to %s: %q"), path, mp_errno_to_str(MP_OBJ_NEW_SMALL_INT(-err)));
+ return mp_const_none;
+ }
+
+ vstr_reset(&self->cur_dir);
+ vstr_add_strn(&self->cur_dir, chdir.buf, lc);
+
+ return mp_const_none;
+}
+static MP_DEFINE_CONST_FUN_OBJ_2(zephyr_fs_chdir_obj, zephyr_fs_chdir);
+
+static mp_obj_t zephyr_fs_getcwd(mp_obj_t vfs_in) {
+ zephyr_fs_obj_t *self = MP_OBJ_TO_PTR(vfs_in);
+ char *path;
+
+ if (vstr_len(&self->cur_dir) == 0) {
+ return MP_OBJ_NEW_QSTR(MP_QSTR__slash_);
+ } else {
+ size_t l = vstr_len(&self->root_dir);
+ size_t lc = vstr_len(&self->cur_dir);
+ vstr_add_str(&self->root_dir, "/");
+ vstr_add_strn(&self->root_dir, self->cur_dir.buf, lc);
+ path = vstr_null_terminated_str(&self->root_dir);
+ self->root_dir.len = l;
+ return mp_obj_new_str_from_cstr(path + l);
+ }
+}
+static MP_DEFINE_CONST_FUN_OBJ_1(zephyr_fs_getcwd_obj, zephyr_fs_getcwd);
+
+static mp_obj_t zephyr_fs_rmdir(mp_obj_t vfs_in, mp_obj_t path_in) {
+ zephyr_fs_obj_t *self = MP_OBJ_TO_PTR(vfs_in);
+ const char *path = zephyr_fs_make_path(self, path_in);
+ struct fs_dirent stats;
+ int err;
+
+ err = fs_stat(path, &stats);
+ if (err < 0) {
+ mp_raise_msg_varg(&mp_type_OSError,
+ MP_ERROR_TEXT("error getting stats of Zephyr File System at %s: %q"), path, mp_errno_to_str(MP_OBJ_NEW_SMALL_INT(-err)));
+ return mp_const_none;
+ }
+ if (stats.type == FS_DIR_ENTRY_FILE) {
+ mp_raise_msg_varg(&mp_type_OSError, MP_ERROR_TEXT("not for removing files"));
+ return mp_const_none;
+ }
+ err = fs_unlink(path);
+ if (err < 0) {
+ mp_raise_msg_varg(&mp_type_OSError,
+ MP_ERROR_TEXT("error removing directory at %s: %q"), path, mp_errno_to_str(MP_OBJ_NEW_SMALL_INT(-err)));
+ }
+ return mp_const_none;
+}
+static MP_DEFINE_CONST_FUN_OBJ_2(zephyr_fs_rmdir_obj, zephyr_fs_rmdir);
+
+static mp_obj_t zephyr_fs_remove(mp_obj_t vfs_in, mp_obj_t path_in) {
+ zephyr_fs_obj_t *self = MP_OBJ_TO_PTR(vfs_in);
+ const char *path = zephyr_fs_make_path(self, path_in);
+ struct fs_dirent stats;
+ int err;
+
+ err = fs_stat(path, &stats);
+ if (err < 0) {
+ mp_raise_msg_varg(&mp_type_OSError,
+ MP_ERROR_TEXT("error getting stats of Zephyr File System at %s: %q"), path, mp_errno_to_str(MP_OBJ_NEW_SMALL_INT(-err)));
+ return mp_const_none;
+ }
+ if (stats.type == FS_DIR_ENTRY_DIR) {
+ mp_raise_msg_varg(&mp_type_OSError, MP_ERROR_TEXT("not for removing directories"));
+ return mp_const_none;
+ }
+ err = fs_unlink(path);
+ if (err < 0) {
+ mp_raise_msg_varg(&mp_type_OSError,
+ MP_ERROR_TEXT("error removing file at %s: %q"), path, mp_errno_to_str(MP_OBJ_NEW_SMALL_INT(-err)));
+ }
+ return mp_const_none;
+}
+static MP_DEFINE_CONST_FUN_OBJ_2(zephyr_fs_remove_obj, zephyr_fs_remove);
+
+static mp_obj_t zephyr_fs_rename(mp_obj_t vfs_in, mp_obj_t path_in, mp_obj_t path_out) {
+ zephyr_fs_obj_t *self = MP_OBJ_TO_PTR(vfs_in);
+ const char *old_path = zephyr_fs_make_path(self, path_in);
+ const char *new_path = zephyr_fs_make_path(self, path_out);
+ int err;
+
+ err = fs_rename(old_path, new_path);
+ if (err < 0) {
+ mp_raise_msg_varg(&mp_type_OSError,
+ MP_ERROR_TEXT("error renaming file from %s to %s: %q"), old_path, new_path, mp_errno_to_str(MP_OBJ_NEW_SMALL_INT(-err)));
+ }
+ return mp_const_none;
+}
+static MP_DEFINE_CONST_FUN_OBJ_3(zephyr_fs_rename_obj, zephyr_fs_rename);
+
+static mp_import_stat_t zephyr_fs_import_stat(void *vfs_in, const char *path) {
+ zephyr_fs_obj_t *self = vfs_in;
+ struct fs_dirent stats;
+ assert(self != NULL);
+ const char *ppath = zephyr_fs_make_path(self, mp_obj_new_str_from_cstr(path));
+ int err;
+
+ err = fs_stat(ppath, &stats);
+ if (err == 0) {
+ if (stats.type == FS_DIR_ENTRY_DIR) {
+ return MP_IMPORT_STAT_DIR;
+ } else {
+ return MP_IMPORT_STAT_FILE;
+ }
+ }
+ return MP_IMPORT_STAT_NO_EXIST;
+}
+
+static mp_obj_t zephyr_fs_stat(mp_obj_t vfs_in, mp_obj_t path_in) {
+ zephyr_fs_obj_t *self = MP_OBJ_TO_PTR(vfs_in);
+ int err;
+ struct fs_dirent stats;
+ const char *path = zephyr_fs_make_path(self, path_in);
+
+ err = fs_stat(path, &stats);
+ if (err < 0) {
+ mp_raise_msg_varg(&mp_type_OSError,
+ MP_ERROR_TEXT("error getting stats of Zephyr File System at %s: %q"), path, mp_errno_to_str(MP_OBJ_NEW_SMALL_INT(-err)));
+ return mp_const_none;
+ }
+
+ mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
+ mp_int_t mode = 0;
+ if (stats.type == FS_DIR_ENTRY_DIR) {
+ mode |= MP_S_IFDIR;
+ } else {
+ mode |= MP_S_IFREG;
+ }
+ t->items[0] = MP_OBJ_NEW_SMALL_INT(mode); // st_mode
+ t->items[1] = MP_OBJ_NEW_SMALL_INT(0); // st_ino
+ t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // st_dev
+ t->items[3] = MP_OBJ_NEW_SMALL_INT(0); // st_nlink
+ t->items[4] = MP_OBJ_NEW_SMALL_INT(0); // st_uid
+ t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // st_gid
+ t->items[6] = mp_obj_new_int_from_uint(stats.size); // st_size
+ t->items[7] = mp_obj_new_int_from_uint(0); // st_atime
+ t->items[8] = mp_obj_new_int_from_uint(0); // st_mtime
+ t->items[9] = mp_obj_new_int_from_uint(0); // st_ctime
+
+ return MP_OBJ_FROM_PTR(t);
+}
+static MP_DEFINE_CONST_FUN_OBJ_2(zephyr_fs_stat_obj, zephyr_fs_stat);
+
+static mp_obj_t zephyr_fs_statvfs(mp_obj_t vfs_in, mp_obj_t path_in) {
+ zephyr_fs_obj_t *self = MP_OBJ_TO_PTR(vfs_in);
+ (void)path_in;
+ int err;
+ struct fs_statvfs stats;
+ unsigned long bsize;
+
+ err = fs_statvfs(self->mount->mnt_point, &stats);
+ if (err < 0) {
+ mp_raise_msg_varg(&mp_type_OSError,
+ MP_ERROR_TEXT("error getting stats of Zephyr File System: %q"), mp_errno_to_str(MP_OBJ_NEW_SMALL_INT(-err)));
+ return mp_const_none;
+ }
+
+ if (stats.f_frsize > stats.f_bsize) {
+ bsize = stats.f_frsize;
+ } else {
+ bsize = stats.f_bsize;
+ }
+
+ mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
+
+ t->items[0] = MP_OBJ_NEW_SMALL_INT(bsize); // f_bsize
+ t->items[1] = MP_OBJ_NEW_SMALL_INT(stats.f_frsize); // f_frsize
+ t->items[2] = MP_OBJ_NEW_SMALL_INT(stats.f_blocks); // f_blocks
+ t->items[3] = MP_OBJ_NEW_SMALL_INT(stats.f_bfree); // f_bfree
+ t->items[4] = t->items[3]; // f_bavail
+ t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // f_files
+ t->items[6] = MP_OBJ_NEW_SMALL_INT(0); // f_ffree
+ t->items[7] = MP_OBJ_NEW_SMALL_INT(0); // f_favail
+ t->items[8] = MP_OBJ_NEW_SMALL_INT(0); // f_flags
+ t->items[9] = MP_OBJ_NEW_SMALL_INT(MAX_FILE_NAME); // f_namemax.
+
+ return MP_OBJ_FROM_PTR(t);
+}
+static MP_DEFINE_CONST_FUN_OBJ_2(zephyr_fs_statvfs_obj, zephyr_fs_statvfs);
+
+static mp_obj_t zephyr_fs_umount(mp_obj_t self_in) {
+ zephyr_fs_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ int err;
+
+ err = fs_unmount(self->mount);
+ if (err < 0) {
+ mp_raise_msg_varg(&mp_type_OSError,
+ MP_ERROR_TEXT("error un-mounting Zephyr File System: %q"), mp_errno_to_str(MP_OBJ_NEW_SMALL_INT(-err)));
+ return mp_const_none;
+ }
+ return mp_const_none;
+}
+static MP_DEFINE_CONST_FUN_OBJ_1(zephyr_fs_umount_obj, zephyr_fs_umount);
+
+static mp_obj_t zephyr_fs_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs) {
+ zephyr_fs_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ int err;
+ (void)readonly;
+ (void)mkfs;
+
+ err = fs_mount(self->mount);
+ if (err == -EBUSY) {
+ err = fs_unmount(self->mount);
+ if (err < 0) {
+ mp_raise_msg_varg(&mp_type_OSError,
+ MP_ERROR_TEXT("error un-mounting Zephyr File System: %q"), mp_errno_to_str(MP_OBJ_NEW_SMALL_INT(-err)));
+ return mp_const_none;
+ }
+ err = fs_mount(self->mount);
+ }
+
+ if (err == -EROFS) {
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("read only filesystem that requires formatting"));
+ return mp_const_none;
+ } else if (err < 0) {
+ mp_raise_msg_varg(&mp_type_OSError,
+ MP_ERROR_TEXT("error mounting Zephyr File System: %q"), mp_errno_to_str(MP_OBJ_NEW_SMALL_INT(-err)));
+ return mp_const_none;
+ }
+
+ return mp_const_none;
+}
+static MP_DEFINE_CONST_FUN_OBJ_3(zephyr_fs_mount_obj, zephyr_fs_mount);
+
+#if CONFIG_FILE_SYSTEM_MKFS
+static mp_obj_t zephyr_fs_mkfs(mp_obj_t self_in) {
+ zephyr_fs_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ // Yes, they correspond indirectly
+ if (self->mount->fs->mkfs((int)self->mount->storage_dev, self->mount->fs_data, self->mount->flags) < 0) {
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("error formatting Zephyr File System"));
+ }
+
+ return mp_const_none;
+}
+
+static MP_DEFINE_CONST_FUN_OBJ_1(zephyr_fs_mkfs_obj, zephyr_fs_mkfs);
+#endif
+
+static mp_obj_t zephyr_fs_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, 1, false);
+
+ if (!mp_obj_is_str(args[0])) {
+ mp_raise_ValueError(MP_ERROR_TEXT("argument must be a zephyr FSTAB mountpoint string"));
+ return mp_const_none;
+ }
+
+ const char *_mountpoint = mp_obj_str_get_str(args[0]);
+ int i = 0;
+
+ for (; i < zephyr_fs_mounts_size; i++) {
+ if (strcmp(_mountpoint, zephyr_fs_mounts[i]->mnt_point) == 0) {
+ break;
+ }
+ }
+
+ if (i == zephyr_fs_mounts_size) {
+ mp_raise_ValueError(MP_ERROR_TEXT("couldn't find zephyr mountpoint"));
+ return mp_const_none;
+ }
+
+ if (zephyr_fs_mounts[i]->fs == 0) {
+ if (fs_mount(zephyr_fs_mounts[i]) != 0) {
+ mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("FS is invalid, try adding automount to fstab"));
+ return mp_const_none;
+ }
+ }
+
+ // create new object
+ zephyr_fs_obj_t *fs = mp_obj_malloc(zephyr_fs_obj_t, type);
+ fs->mount = zephyr_fs_mounts[i];
+ vstr_init(&fs->cur_dir, 32);
+ vstr_init(&fs->root_dir, 128);
+ vstr_add_str(&fs->root_dir, zephyr_fs_mounts[i]->mnt_point);
+
+ return MP_OBJ_FROM_PTR(fs);
+}
+
+static mp_obj_t zephyr_fs_fstab(void) {
+ mp_obj_t list = mp_obj_new_list(0, NULL);
+
+ for (int i = 0; i < zephyr_fs_mounts_size; i++) {
+ mp_obj_list_append(list, mp_obj_new_str_from_cstr(zephyr_fs_mounts[i]->mnt_point));
+ }
+
+ return list;
+}
+static MP_DEFINE_CONST_FUN_OBJ_0(zephyr_fs_fstab_fun_obj, zephyr_fs_fstab);
+static MP_DEFINE_CONST_STATICMETHOD_OBJ(zephyr_fs_fstab_obj, MP_ROM_PTR(&zephyr_fs_fstab_fun_obj));
+
+static const mp_rom_map_elem_t zephyr_fs_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&zephyr_fs_mount_obj) },
+ { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&zephyr_fs_umount_obj) },
+ { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&zephyr_fs_statvfs_obj) },
+ { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&zephyr_fs_stat_obj) },
+ { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&zephyr_fs_rename_obj) },
+ { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&zephyr_fs_remove_obj) },
+ { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&zephyr_fs_rmdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&zephyr_fs_getcwd_obj) },
+ { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&zephyr_fs_chdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&zephyr_fs_mkdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&zephyr_fs_open_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&zephyr_fs_ilistdir_obj) },
+ #if CONFIG_FILE_SYSTEM_MKFS
+ { MP_ROM_QSTR(MP_QSTR_mkfs), MP_ROM_PTR(&zephyr_fs_mkfs_obj) },
+ #endif
+ // Not part of the VFS API, used to list available File Systems
+ { MP_ROM_QSTR(MP_QSTR_fstab), MP_ROM_PTR(&zephyr_fs_fstab_obj) },
+};
+static MP_DEFINE_CONST_DICT(zephyr_fs_locals_dict, zephyr_fs_locals_dict_table);
+
+static const mp_vfs_proto_t zephyr_fs_proto = {
+ .import_stat = zephyr_fs_import_stat,
+};
+
+const mp_obj_type_t zephyr_filesystem_type;
+
+MP_DEFINE_CONST_OBJ_TYPE(
+ zephyr_filesystem_type,
+ MP_QSTR_FileSystem,
+ MP_TYPE_FLAG_NONE,
+ make_new, zephyr_fs_make_new,
+ protocol, &zephyr_fs_proto,
+ locals_dict, &zephyr_fs_locals_dict
+ );
+
+#endif // CONFIG_FILE_SYSTEM