esp32/boards/ARDUINO_NANO_ESP32: Add support for Arduino Nano ESP32.
Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
This commit is contained in:
parent
e0784750aa
commit
cc9735ad6a
|
@ -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"
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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
|
||||
```
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -0,0 +1,9 @@
|
|||
include("$(PORT_DIR)/boards/manifest.py")
|
||||
|
||||
# Utils
|
||||
require("time")
|
||||
require("senml")
|
||||
require("logging")
|
||||
|
||||
# Bluetooth
|
||||
require("aioble")
|
|
@ -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)
|
|
@ -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);
|
|
@ -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,
|
|
|
@ -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
|
|
|
@ -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
|
Loading…
Reference in New Issue