Skip to content

Commit

Permalink
[pin_remap 3/3]: add Arduino Nano ESP32 board
Browse files Browse the repository at this point in the history
  • Loading branch information
pillo79 committed Nov 23, 2023
1 parent 287254b commit ea46fe9
Show file tree
Hide file tree
Showing 16 changed files with 768 additions and 3 deletions.
71 changes: 70 additions & 1 deletion boards.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ menu.MemoryType=Memory Type
menu.EraseFlash=Erase All Flash Before Sketch Upload
menu.JTAGAdapter=JTAG Adapter
menu.ZigbeeMode=Zigbee Mode
menu.PinNumbers=Pin Numbering

# Custom options
menu.Revision=Board Revision
Expand Down Expand Up @@ -29688,4 +29689,72 @@ sensebox_mcu_esp32s2.menu.EraseFlash.none.upload.erase_cmd=
sensebox_mcu_esp32s2.menu.EraseFlash.all=Enabled
sensebox_mcu_esp32s2.menu.EraseFlash.all.upload.erase_cmd=-e

##############################################################
##############################################################

nano_nora.name=Arduino Nano ESP32
nano_nora.vid.0=0x2341
nano_nora.pid.0=0x0070
nano_nora.upload_port.0.vid=0x2341
nano_nora.upload_port.0.pid=0x0070

nano_nora.bootloader.tool=esptool_py
nano_nora.bootloader.tool.default=esptool_py

nano_nora.upload.tool=dfu-util
nano_nora.upload.tool.default=dfu-util
nano_nora.upload.tool.network=esp_ota
nano_nora.upload.protocol=serial
nano_nora.upload.maximum_size=3145728
nano_nora.upload.maximum_data_size=327680
nano_nora.upload.use_1200bps_touch=false
nano_nora.upload.wait_for_upload_port=false

nano_nora.serial.disableDTR=false
nano_nora.serial.disableRTS=false

nano_nora.build.tarch=xtensa
nano_nora.build.bootloader_addr=0x0
nano_nora.build.target=esp32s3
nano_nora.build.mcu=esp32s3
nano_nora.build.core=esp32
nano_nora.build.variant=arduino_nano_nora
nano_nora.build.board=NANO_ESP32
nano_nora.build.code_debug=0

nano_nora.build.usb_mode=0
nano_nora.build.cdc_on_boot=1
nano_nora.build.msc_on_boot=0
nano_nora.build.dfu_on_boot=1
nano_nora.build.f_cpu=240000000L
nano_nora.build.flash_size=16MB
nano_nora.build.flash_freq=80m
nano_nora.build.flash_mode=dio
nano_nora.build.boot=qio
nano_nora.build.boot_freq=80m
nano_nora.build.partitions=app3M_fat9M_fact512k_16MB
nano_nora.build.defines=-DBOARD_HAS_PIN_REMAP {build.disable_pin_remap} -DBOARD_HAS_PSRAM '-DUSB_MANUFACTURER="Arduino"' '-DUSB_PRODUCT="Nano ESP32"'
nano_nora.build.loop_core=-DARDUINO_RUNNING_CORE=1
nano_nora.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1
nano_nora.build.psram_type=opi
nano_nora.build.memory_type={build.boot}_{build.psram_type}
nano_nora.build.disable_pin_remap=

nano_nora.tools.esptool_py.program.pattern_args=--chip {build.mcu} --port "{serial.port}" --before default_reset --after hard_reset write_flash -z --flash_mode {build.flash_mode} --flash_freq {build.flash_freq} --flash_size {build.flash_size} {build.bootloader_addr} "{build.path}/{build.project_name}.bootloader.bin" 0x8000 "{build.path}/{build.project_name}.partitions.bin" 0xe000 "{runtime.platform.path}/tools/partitions/boot_app0.bin" 0xf70000 "{build.variant.path}/extra/nora_recovery/nora_recovery.ino.bin" 0x10000 "{build.path}/{build.project_name}.bin"
nano_nora.tools.esptool_py.erase.pattern_args=--chip {build.mcu} --port "{serial.port}" --before default_reset --after hard_reset erase_flash

nano_nora.menu.PartitionScheme.default=With FAT partition (default)
nano_nora.menu.PartitionScheme.spiffs=With SPIFFS partition (advanced)
nano_nora.menu.PartitionScheme.spiffs.build.partitions=app3M_spiffs9M_fact512k_16MB

nano_nora.menu.PinNumbers.default=By Arduino pin (default)
nano_nora.menu.PinNumbers.byGPIONumber=By GPIO number (legacy)
nano_nora.menu.PinNumbers.byGPIONumber.build.disable_pin_remap=-DBOARD_USES_HW_GPIO_NUMBERS

nano_nora.menu.USBMode.default=Normal mode (TinyUSB)
nano_nora.menu.USBMode.hwcdc=Debug mode (Hardware CDC)
nano_nora.menu.USBMode.hwcdc.build.usb_mode=1
nano_nora.menu.USBMode.hwcdc.build.copy_jtag_files=1
nano_nora.menu.USBMode.hwcdc.build.openocdscript=esp32s3-builtin.cfg
nano_nora.menu.USBMode.hwcdc.build.debugconfig=esp32s3-arduino.json

##############################################################
13 changes: 11 additions & 2 deletions cores/esp32/USB.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,11 @@
#define USB_WEBUSB_URL "https://espressif.github.io/arduino-esp32/webusb.html"
#endif

#if CFG_TUD_DFU_RUNTIME
#if CFG_TUD_DFU
__attribute__((weak)) uint16_t load_dfu_ota_descriptor(uint8_t * dst, uint8_t * itf) {
return 0;
}
#elif CFG_TUD_DFU_RUNTIME
static uint16_t load_dfu_descriptor(uint8_t * dst, uint8_t * itf)
{
#define DFU_ATTRS (DFU_ATTR_CAN_DOWNLOAD | DFU_ATTR_CAN_UPLOAD | DFU_ATTR_MANIFESTATION_TOLERANT)
Expand All @@ -65,6 +69,9 @@ static uint16_t load_dfu_descriptor(uint8_t * dst, uint8_t * itf)
memcpy(dst, descriptor, TUD_DFU_RT_DESC_LEN);
return TUD_DFU_RT_DESC_LEN;
}
#endif /* CFG_TUD_DFU_RUNTIME */

#if CFG_TUD_DFU_RUNTIME
// Invoked on DFU_DETACH request to reboot to the bootloader
void tud_dfu_runtime_reboot_to_dfu_cb(void)
{
Expand Down Expand Up @@ -207,7 +214,9 @@ ESPUSB::operator bool() const
}

bool ESPUSB::enableDFU(){
#if CFG_TUD_DFU_RUNTIME
#if CFG_TUD_DFU
return tinyusb_enable_interface(USB_INTERFACE_DFU, TUD_DFU_DESC_LEN(1), load_dfu_ota_descriptor) == ESP_OK;
#elif CFG_TUD_DFU_RUNTIME
return tinyusb_enable_interface(USB_INTERFACE_DFU, TUD_DFU_RT_DESC_LEN, load_dfu_descriptor) == ESP_OK;
#endif /* CFG_TUD_DFU_RUNTIME */
return false;
Expand Down
8 changes: 8 additions & 0 deletions package/package_esp32_index.template.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
},
{
"name": "ESP32-C3 Dev Board"
},
{
"name": "Arduino Nano ESP32"
}
],
"toolsDependencies": [
Expand Down Expand Up @@ -90,6 +93,11 @@
"packager": "esp32",
"name": "mklittlefs",
"version": "3.0.0-gnu12-dc7f933"
},
{
"packager": "arduino",
"name": "dfu-util",
"version": "0.11.0-arduino5"
}
]
}
Expand Down
8 changes: 8 additions & 0 deletions platform.txt
Original file line number Diff line number Diff line change
Expand Up @@ -277,3 +277,11 @@ tools.esp_ota.upload.protocol=network
tools.esp_ota.upload.field.password=Password
tools.esp_ota.upload.field.password.secret=true
tools.esp_ota.upload.pattern={cmd} -i {upload.port.address} -p {upload.port.properties.port} --auth={upload.field.password} -f "{build.path}/{build.project_name}.bin"

## Upload Sketch Through DFU OTA
## -------------------------------------------
tools.dfu-util.path={runtime.tools.dfu-util-0.11.0-arduino5.path}
tools.dfu-util.cmd=dfu-util
tools.dfu-util.upload.params.verbose=-d
tools.dfu-util.upload.params.quiet=
tools.dfu-util.upload.pattern="{path}/{cmd}" --device {vid.0}:{pid.0} -D "{build.path}/{build.project_name}.bin" -Q
18 changes: 18 additions & 0 deletions tools/ide-debug/esp32s3-arduino.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name":"Arduino on ESP32-S3",
"toolchainPrefix":"xtensa-esp32s3-elf",
"svdFile":"debug.svd",
"request":"attach",
"overrideAttachCommands":[
"set remote hardware-watchpoint-limit 2",
"monitor reset halt",
"monitor gdb_sync",
"thb setup",
"interrupt"
],
"overrideRestartCommands":[
"monitor reset halt",
"monitor gdb_sync",
"interrupt"
]
}
9 changes: 9 additions & 0 deletions tools/partitions/app3M_fat9M_fact512k_16MB.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# 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,
# to create/use ffat, see https://github.com/marcmerlin/esp32_fatfsimage
8 changes: 8 additions & 0 deletions tools/partitions/app3M_spiffs9M_fact512k_16MB.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# 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,
spiffs, data, spiffs, 0x610000, 0x960000,
factory, app, factory, 0xF70000, 0x80000,
coredump, data, coredump, 0xFF0000, 0x10000,
116 changes: 116 additions & 0 deletions variants/arduino_nano_nora/dfu_callbacks.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#include "Arduino.h"

#include <esp32-hal-tinyusb.h>
#include <esp_system.h>

// defines an "Update" object accessed only by this translation unit
// (also, the object requires MD5Builder internally)
namespace {
// ignore '{anonymous}::MD5Builder::...() defined but not used' warnings
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
#include "../../libraries/Update/src/Updater.cpp"
#include "../../cores/esp32/MD5Builder.cpp"
#pragma GCC diagnostic pop
}

#define ALT_COUNT 1

//--------------------------------------------------------------------+
// DFU callbacks
// Note: alt is used as the partition number, in order to support multiple partitions like FLASH, EEPROM, etc.
//--------------------------------------------------------------------+

uint16_t load_dfu_ota_descriptor(uint8_t * dst, uint8_t * itf)
{
#define DFU_ATTRS (DFU_ATTR_CAN_DOWNLOAD | DFU_ATTR_CAN_UPLOAD | DFU_ATTR_MANIFESTATION_TOLERANT)

uint8_t str_index = tinyusb_add_string_descriptor("Arduino DFU");
uint8_t descriptor[TUD_DFU_DESC_LEN(ALT_COUNT)] = {
// Interface number, string index, attributes, detach timeout, transfer size */
TUD_DFU_DESCRIPTOR(*itf, ALT_COUNT, str_index, DFU_ATTRS, 100, CFG_TUD_DFU_XFER_BUFSIZE),
};
*itf+=1;
memcpy(dst, descriptor, TUD_DFU_DESC_LEN(ALT_COUNT));
return TUD_DFU_DESC_LEN(ALT_COUNT);
}

// Invoked right before tud_dfu_download_cb() (state=DFU_DNBUSY) or tud_dfu_manifest_cb() (state=DFU_MANIFEST)
// Application return timeout in milliseconds (bwPollTimeout) for the next download/manifest operation.
// During this period, USB host won't try to communicate with us.
uint32_t tud_dfu_get_timeout_cb(uint8_t alt, uint8_t state)
{
if ( state == DFU_DNBUSY )
{
// longest delay for Flash writing
return 10;
}
else if (state == DFU_MANIFEST)
{
// time for esp32_ota_set_boot_partition to check final image
return 100;
}

return 0;
}

// Invoked when received DFU_DNLOAD (wLength>0) following by DFU_GETSTATUS (state=DFU_DNBUSY) requests
// This callback could be returned before flashing op is complete (async).
// Once finished flashing, application must call tud_dfu_finish_flashing()
void tud_dfu_download_cb(uint8_t alt, uint16_t block_num, uint8_t const* data, uint16_t length)
{
if (!Update.isRunning())
{
// this is the first data block, start update if possible
if (!Update.begin())
{
tud_dfu_finish_flashing(DFU_STATUS_ERR_TARGET);
return;
}
}

// write a block of data to Flash
// XXX: Update API is needlessly non-const
size_t written = Update.write(const_cast<uint8_t*>(data), length);
tud_dfu_finish_flashing((written == length) ? DFU_STATUS_OK : DFU_STATUS_ERR_WRITE);
}

// Invoked when download process is complete, received DFU_DNLOAD (wLength=0) following by DFU_GETSTATUS (state=Manifest)
// Application can do checksum, or actual flashing if buffered entire image previously.
// Once finished flashing, application must call tud_dfu_finish_flashing()
void tud_dfu_manifest_cb(uint8_t alt)
{
(void) alt;
bool ok = Update.end(true);

// flashing op for manifest is complete
tud_dfu_finish_flashing(ok? DFU_STATUS_OK : DFU_STATUS_ERR_VERIFY);
}

// Invoked when received DFU_UPLOAD request
// Application must populate data with up to length bytes and
// Return the number of written bytes
uint16_t tud_dfu_upload_cb(uint8_t alt, uint16_t block_num, uint8_t* data, uint16_t length)
{
(void) alt;
(void) block_num;
(void) data;
(void) length;

// not implemented
return 0;
}

// Invoked when the Host has terminated a download or upload transfer
void tud_dfu_abort_cb(uint8_t alt)
{
(void) alt;
// ignore
}

// Invoked when a DFU_DETACH request is received
void tud_dfu_detach_cb(void)
{
// done, reboot
esp_restart();
}
68 changes: 68 additions & 0 deletions variants/arduino_nano_nora/double_tap.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#include <string.h>

#include <esp_system.h>
#include <esp32s3/rom/cache.h>
#include <esp_heap_caps.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];

#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
// 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.
#include <esp_psram.h>
#include <esp_private/esp_psram_extram.h>
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();
}
#else
#include <soc/soc.h>
#define get_extram_data_high() ((uintptr_t) SOC_EXTRAM_DATA_HIGH)
#endif


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);
}
20 changes: 20 additions & 0 deletions variants/arduino_nano_nora/double_tap.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#ifndef __DOUBLE_TAP_H__
#define __DOUBLE_TAP_H__

#include <stdint.h>
#include <stdbool.h>

#ifdef __cplusplus
extern "C" {
#endif

void double_tap_init(void);
void double_tap_mark(void);
void double_tap_invalidate(void);
bool double_tap_check_match(void);

#ifdef __cplusplus
}
#endif

#endif /* __DOUBLE_TAP_H__ */
Loading

0 comments on commit ea46fe9

Please sign in to comment.