summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ports/esp32/boards/ARDUINO_NANO_ESP32/board.json20
-rw-r--r--ports/esp32/boards/ARDUINO_NANO_ESP32/board_init.c124
-rw-r--r--ports/esp32/boards/ARDUINO_NANO_ESP32/deploy.md8
-rw-r--r--ports/esp32/boards/ARDUINO_NANO_ESP32/double_tap.c89
-rw-r--r--ports/esp32/boards/ARDUINO_NANO_ESP32/double_tap.h37
-rw-r--r--ports/esp32/boards/ARDUINO_NANO_ESP32/manifest.py9
-rw-r--r--ports/esp32/boards/ARDUINO_NANO_ESP32/mpconfigboard.cmake23
-rw-r--r--ports/esp32/boards/ARDUINO_NANO_ESP32/mpconfigboard.h32
-rw-r--r--ports/esp32/boards/ARDUINO_NANO_ESP32/partitions-app3M_fat9M_fact512k_16MiB.csv10
-rw-r--r--ports/esp32/boards/ARDUINO_NANO_ESP32/pins.csv38
-rw-r--r--ports/esp32/boards/ARDUINO_NANO_ESP32/sdkconfig.board22
11 files changed, 412 insertions, 0 deletions
diff --git a/ports/esp32/boards/ARDUINO_NANO_ESP32/board.json b/ports/esp32/boards/ARDUINO_NANO_ESP32/board.json
new file mode 100644
index 000000000..031ee1741
--- /dev/null
+++ b/ports/esp32/boards/ARDUINO_NANO_ESP32/board.json
@@ -0,0 +1,20 @@
+{
+ "deploy": [
+ "../deploy_s3.md"
+ ],
+ "docs": "",
+ "features": [
+ "BLE",
+ "WiFi",
+ "USB-C",
+ "RGB LED"
+ ],
+ "images": [
+ "ABX00092_01.iso_1000x750.jpg"
+ ],
+ "mcu": "esp32s3",
+ "product": "Arduino Nano ESP32",
+ "thumbnail": "",
+ "url": "https://store.arduino.cc/products/arduino-nano-esp32",
+ "vendor": "Arduino"
+}
diff --git a/ports/esp32/boards/ARDUINO_NANO_ESP32/board_init.c b/ports/esp32/boards/ARDUINO_NANO_ESP32/board_init.c
new file mode 100644
index 000000000..ab03139d9
--- /dev/null
+++ b/ports/esp32/boards/ARDUINO_NANO_ESP32/board_init.c
@@ -0,0 +1,124 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2023 Arduino SA
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+#include "py/mphal.h"
+
+#include <esp_system.h>
+#include <esp_ota_ops.h>
+#include <esp_partition.h>
+
+#include "double_tap.h"
+#include "usb.h"
+
+#include "tinyusb.h"
+#include "tusb_cdc_acm.h"
+
+#define LED_RED GPIO_NUM_46
+#define LED_GREEN GPIO_NUM_0
+#define LED_BLUE GPIO_NUM_45
+#define DELAY_US 60000
+
+static bool _recovery_marker_found; // double tap detected
+static bool _recovery_active; // running from factory partition
+
+static void rgb_pulse_delay() {
+ // initialize RGB signals from weak pinstraps
+ mp_hal_pin_output(LED_RED);
+ mp_hal_pin_output(LED_GREEN);
+ mp_hal_pin_output(LED_BLUE);
+
+ static const uint8_t SEQ[] = { 1, 3, 2, 6, 7, 5, 4, 5, 7, 6, 2, 3, 1 };
+ for (int idx = 0; idx < sizeof(SEQ); ++idx) {
+ int v = SEQ[idx & 7];
+ mp_hal_pin_write(LED_RED, !(v & 1));
+ mp_hal_pin_write(LED_GREEN, !(v & 2));
+ mp_hal_pin_write(LED_BLUE, !(v & 4));
+
+ // busy wait, we can't use task delay yet
+ mp_hal_delay_us_fast(DELAY_US);
+ }
+
+ // reset pins to digital HIGH before leaving
+ mp_hal_pin_write(LED_RED, 1);
+ mp_hal_pin_write(LED_GREEN, 1);
+ mp_hal_pin_write(LED_BLUE, 1);
+}
+
+void NANO_ESP32_enter_bootloader(void) {
+ if (!_recovery_active) {
+ // check for valid partition scheme
+ const esp_partition_t *ota_part = esp_ota_get_next_update_partition(NULL);
+ const esp_partition_t *fact_part = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL);
+ if (ota_part && fact_part) {
+ // set tokens so the recovery FW will find them
+ double_tap_mark();
+ // invalidate other OTA image
+ esp_partition_erase_range(ota_part, 0, 4096);
+ // activate factory partition
+ esp_ota_set_boot_partition(fact_part);
+ }
+ }
+
+ esp_restart();
+}
+
+void NANO_ESP32_usb_callback_line_state_changed(int itf, void *event_in) {
+ extern void mp_usbd_line_state_cb(uint8_t itf, bool dtr, bool rts);
+ cdcacm_event_t *event = event_in;
+ mp_usbd_line_state_cb(itf, event->line_state_changed_data.dtr, event->line_state_changed_data.rts);
+}
+
+void NANO_ESP32_board_startup(void) {
+ boardctrl_startup();
+
+ // mark current partition as valid
+ const esp_partition_t *running = esp_ota_get_running_partition();
+ esp_ota_img_states_t ota_state;
+ if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) {
+ if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) {
+ esp_ota_mark_app_valid_cancel_rollback();
+ }
+ }
+
+ const esp_partition_t *part = esp_ota_get_running_partition();
+ _recovery_active = (part->subtype == ESP_PARTITION_SUBTYPE_APP_FACTORY);
+
+ double_tap_init();
+
+ _recovery_marker_found = double_tap_check_match();
+ if (_recovery_marker_found && !_recovery_active) {
+ // double tap detected in user application, reboot to factory
+ NANO_ESP32_enter_bootloader();
+ }
+
+ // delay with mark set then proceed
+ // - for normal startup, to detect first double tap
+ // - in recovery mode, to ignore several short presses
+ double_tap_mark();
+ rgb_pulse_delay();
+ double_tap_invalidate();
+}
diff --git a/ports/esp32/boards/ARDUINO_NANO_ESP32/deploy.md b/ports/esp32/boards/ARDUINO_NANO_ESP32/deploy.md
new file mode 100644
index 000000000..b600a55b6
--- /dev/null
+++ b/ports/esp32/boards/ARDUINO_NANO_ESP32/deploy.md
@@ -0,0 +1,8 @@
+### Via dfu-util
+
+This board can programmed via DFU bootloader, using e.g. [dfu-util](http://dfu-util.sourceforge.net/).
+To enter the DFU bootloader, double tap the reset (blue) button, or you can use `machine.bootloader()` from the MicroPython REPL.
+
+```bash
+dfu-util -d 0x2341:0x0070 -R -D build-ARDUINO_NANO_ESP32/micropython.bin
+```
diff --git a/ports/esp32/boards/ARDUINO_NANO_ESP32/double_tap.c b/ports/esp32/boards/ARDUINO_NANO_ESP32/double_tap.c
new file mode 100644
index 000000000..8f50a3272
--- /dev/null
+++ b/ports/esp32/boards/ARDUINO_NANO_ESP32/double_tap.c
@@ -0,0 +1,89 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2023 Arduino SA
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+#include "py/mphal.h"
+
+#include <esp32s3/rom/cache.h>
+
+// for get_extram_data_high()
+#include <esp_psram.h>
+#include <esp_private/esp_psram_extram.h>
+
+#include "double_tap.h"
+
+#define NUM_TOKENS 3
+static const uint32_t MAGIC_TOKENS[NUM_TOKENS] = {
+ 0xf01681de, 0xbd729b29, 0xd359be7a,
+};
+
+static void *magic_area;
+static uint32_t backup_area[NUM_TOKENS];
+
+// Current IDF does not map external RAM to a fixed address.
+// The actual VMA depends on other enabled devices, so the precise
+// location must be discovered.
+static uintptr_t get_extram_data_high(void) {
+ // get a pointer into SRAM area (only the address is useful)
+ void *psram_ptr = heap_caps_malloc(16, MALLOC_CAP_SPIRAM);
+ heap_caps_free(psram_ptr);
+
+ // keep moving backwards until leaving PSRAM area
+ uintptr_t psram_base_addr = (uintptr_t)psram_ptr;
+ psram_base_addr &= ~(CONFIG_MMU_PAGE_SIZE - 1); // align to start of page
+ while (esp_psram_check_ptr_addr((void *)psram_base_addr)) {
+ psram_base_addr -= CONFIG_MMU_PAGE_SIZE;
+ }
+
+ // offset is one page from start of PSRAM
+ return psram_base_addr + CONFIG_MMU_PAGE_SIZE + esp_psram_get_size();
+}
+
+void double_tap_init(void) {
+ // magic location block ends 0x20 bytes from end of PSRAM
+ magic_area = (void *)(get_extram_data_high() - 0x20 - sizeof(MAGIC_TOKENS));
+}
+
+void double_tap_mark() {
+ memcpy(backup_area, magic_area, sizeof(MAGIC_TOKENS));
+ memcpy(magic_area, MAGIC_TOKENS, sizeof(MAGIC_TOKENS));
+ Cache_WriteBack_Addr((uintptr_t)magic_area, sizeof(MAGIC_TOKENS));
+}
+
+void double_tap_invalidate() {
+ if (memcmp(backup_area, MAGIC_TOKENS, sizeof(MAGIC_TOKENS))) {
+ // different contents: restore backup
+ memcpy(magic_area, backup_area, sizeof(MAGIC_TOKENS));
+ } else {
+ // clear memory
+ memset(magic_area, 0, sizeof(MAGIC_TOKENS));
+ }
+ Cache_WriteBack_Addr((uintptr_t)magic_area, sizeof(MAGIC_TOKENS));
+}
+
+bool double_tap_check_match() {
+ return memcmp(magic_area, MAGIC_TOKENS, sizeof(MAGIC_TOKENS)) == 0;
+}
diff --git a/ports/esp32/boards/ARDUINO_NANO_ESP32/double_tap.h b/ports/esp32/boards/ARDUINO_NANO_ESP32/double_tap.h
new file mode 100644
index 000000000..9aa738f2d
--- /dev/null
+++ b/ports/esp32/boards/ARDUINO_NANO_ESP32/double_tap.h
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2023 Arduino SA
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_ESP32_DOUBLE_TAP_H
+#define MICROPY_INCLUDED_ESP32_DOUBLE_TAP_H
+
+#include <stdint.h>
+
+void double_tap_init(void);
+void double_tap_mark(void);
+void double_tap_invalidate(void);
+bool double_tap_check_match(void);
+
+#endif /* MICROPY_INCLUDED_ESP32_DOUBLE_TAP_H */
diff --git a/ports/esp32/boards/ARDUINO_NANO_ESP32/manifest.py b/ports/esp32/boards/ARDUINO_NANO_ESP32/manifest.py
new file mode 100644
index 000000000..e7fc7fe16
--- /dev/null
+++ b/ports/esp32/boards/ARDUINO_NANO_ESP32/manifest.py
@@ -0,0 +1,9 @@
+include("$(PORT_DIR)/boards/manifest.py")
+
+# Utils
+require("time")
+require("senml")
+require("logging")
+
+# Bluetooth
+require("aioble")
diff --git a/ports/esp32/boards/ARDUINO_NANO_ESP32/mpconfigboard.cmake b/ports/esp32/boards/ARDUINO_NANO_ESP32/mpconfigboard.cmake
new file mode 100644
index 000000000..7ae4b3818
--- /dev/null
+++ b/ports/esp32/boards/ARDUINO_NANO_ESP32/mpconfigboard.cmake
@@ -0,0 +1,23 @@
+if(NOT MICROPY_DIR)
+ get_filename_component(MICROPY_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../.. ABSOLUTE)
+endif()
+
+set(IDF_TARGET esp32s3)
+
+set(SDKCONFIG_DEFAULTS
+ boards/sdkconfig.base
+ boards/sdkconfig.usb
+ boards/sdkconfig.ble
+ boards/sdkconfig.240mhz
+ boards/sdkconfig.spiram_sx
+ boards/sdkconfig.spiram_oct
+ ${MICROPY_BOARD_DIR}/sdkconfig.board
+)
+
+set(MICROPY_SOURCE_BOARD
+ ${MICROPY_BOARD_DIR}/board_init.c
+ ${MICROPY_BOARD_DIR}/double_tap.c
+ ${MICROPY_DIR}/shared/tinyusb/mp_cdc_common.c
+)
+
+set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
diff --git a/ports/esp32/boards/ARDUINO_NANO_ESP32/mpconfigboard.h b/ports/esp32/boards/ARDUINO_NANO_ESP32/mpconfigboard.h
new file mode 100644
index 000000000..3e98bb99d
--- /dev/null
+++ b/ports/esp32/boards/ARDUINO_NANO_ESP32/mpconfigboard.h
@@ -0,0 +1,32 @@
+#define MICROPY_HW_BOARD_NAME "Arduino Nano ESP32"
+#define MICROPY_HW_MCU_NAME "ESP32S3"
+
+#define MICROPY_PY_MACHINE_DAC (0)
+
+#define MICROPY_HW_I2C0_SCL (12)
+#define MICROPY_HW_I2C0_SDA (11)
+
+#define MICROPY_HW_I2C1_SCL (8)
+#define MICROPY_HW_I2C1_SDA (9)
+
+#define MICROPY_HW_SPI1_MOSI (38)
+#define MICROPY_HW_SPI1_MISO (47)
+#define MICROPY_HW_SPI1_SCK (48)
+
+#define MICROPY_HW_SPI2_MOSI (10)
+#define MICROPY_HW_SPI2_MISO (17)
+#define MICROPY_HW_SPI2_SCK (18)
+
+#define MICROPY_HW_ENABLE_USBDEV (1)
+#define MICROPY_HW_USB_EXTERNAL_TINYUSB (1)
+#define MICROPY_HW_USB_CDC_1200BPS_TOUCH (1)
+#define MICROPY_SCHEDULER_STATIC_NODES (1)
+
+#define MICROPY_HW_USB_CUSTOM_LINE_STATE_CB NANO_ESP32_usb_callback_line_state_changed
+void NANO_ESP32_usb_callback_line_state_changed(int itf, void *event);
+
+#define MICROPY_BOARD_STARTUP NANO_ESP32_board_startup
+void NANO_ESP32_board_startup(void);
+
+#define MICROPY_BOARD_ENTER_BOOTLOADER(nargs, args) NANO_ESP32_enter_bootloader()
+void NANO_ESP32_enter_bootloader(void);
diff --git a/ports/esp32/boards/ARDUINO_NANO_ESP32/partitions-app3M_fat9M_fact512k_16MiB.csv b/ports/esp32/boards/ARDUINO_NANO_ESP32/partitions-app3M_fat9M_fact512k_16MiB.csv
new file mode 100644
index 000000000..13b4414b1
--- /dev/null
+++ b/ports/esp32/boards/ARDUINO_NANO_ESP32/partitions-app3M_fat9M_fact512k_16MiB.csv
@@ -0,0 +1,10 @@
+# Notes: the offset of the partition table itself is set in
+# $IDF_PATH/components/partition_table/Kconfig.projbuild.
+# Name, Type, SubType, Offset, Size, Flags
+nvs, data, nvs, 0x9000, 0x5000,
+otadata, data, ota, 0xe000, 0x2000,
+app0, app, ota_0, 0x10000, 0x300000,
+app1, app, ota_1, 0x310000, 0x300000,
+ffat, data, fat, 0x610000, 0x960000,
+factory, app, factory, 0xF70000, 0x80000,
+coredump, data, coredump, 0xFF0000, 0x10000,
diff --git a/ports/esp32/boards/ARDUINO_NANO_ESP32/pins.csv b/ports/esp32/boards/ARDUINO_NANO_ESP32/pins.csv
new file mode 100644
index 000000000..b891608d5
--- /dev/null
+++ b/ports/esp32/boards/ARDUINO_NANO_ESP32/pins.csv
@@ -0,0 +1,38 @@
+D0,GPIO44
+D1,GPIO43
+D2,GPIO5
+D3,GPIO6
+D4,GPIO7
+D5,GPIO8
+D6,GPIO9
+D7,GPIO10
+D8,GPIO17
+D9,GPIO18
+D10,GPIO21
+D11,GPIO38
+D12,GPIO47
+D13,GPIO48
+LED_RED,GPIO46
+LED_GREEN,GPIO0
+LED_BLUE,GPIO45
+A0,GPIO1
+A1,GPIO2
+A2,GPIO3
+A3,GPIO4
+A4,GPIO11
+A5,GPIO12
+A6,GPIO13
+A7,GPIO14
+LED_BUILTIN,GPIO48
+TX,GPIO43
+RX,GPIO44
+RTS,GPIO45
+CTS,GPIO6
+DTR,GPIO1
+DSR,GPIO7
+SS,GPIO21
+MOSI,GPIO38
+MISO,GPIO47
+SCK,GPIO48
+SDA,GPIO11
+SCL,GPIO12
diff --git a/ports/esp32/boards/ARDUINO_NANO_ESP32/sdkconfig.board b/ports/esp32/boards/ARDUINO_NANO_ESP32/sdkconfig.board
new file mode 100644
index 000000000..4d175f7ed
--- /dev/null
+++ b/ports/esp32/boards/ARDUINO_NANO_ESP32/sdkconfig.board
@@ -0,0 +1,22 @@
+CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
+CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y
+CONFIG_PARTITION_TABLE_CUSTOM=y
+CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="boards/ARDUINO_NANO_ESP32/partitions-app3M_fat9M_fact512k_16MiB.csv"
+
+CONFIG_SPIRAM_TYPE_ESPPSRAM64=y
+CONFIG_SPIRAM_SPEED_80M=y
+CONFIG_SPIRAM_MEMTEST=
+CONFIG_SPIRAM_IGNORE_NOTFOUND=
+
+CONFIG_LWIP_LOCAL_HOSTNAME="nano-esp32"
+
+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_APP_ROLLBACK_ENABLE=y
+CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP=y
+CONFIG_ESP_ENABLE_COREDUMP_TO_FLASH=y