From 4716e66d1b21b7be15cd0956a41740a4eb650605 Mon Sep 17 00:00:00 2001 From: "mia.metzler" Date: Sat, 20 Sep 2025 18:01:23 +0200 Subject: [PATCH 1/3] feat: Add ESP32 bsp support --- _Boards/esp32s3.board.json | 60 ++++++++++++++++++++++++++++++++++++++ copy_fw_files.py | 6 +++- platformio.ini | 21 +++++++++++++ src/Config.cpp | 34 ++++++++++++++++++--- src/MF_Analog/MFAnalog.cpp | 5 +++- src/MF_Output/MFOutput.cpp | 5 +++- src/MF_Servo/MFServo.cpp | 4 ++- src/MF_Servo/MFServo.h | 4 +++ src/allocateMem.cpp | 5 ++-- src/allocateMem.h | 2 +- 10 files changed, 135 insertions(+), 11 deletions(-) create mode 100644 _Boards/esp32s3.board.json diff --git a/_Boards/esp32s3.board.json b/_Boards/esp32s3.board.json new file mode 100644 index 00000000..acff7dbe --- /dev/null +++ b/_Boards/esp32s3.board.json @@ -0,0 +1,60 @@ +{ + "$schema": "./mfboard.schema.json", + "UsbDriveSettings": {}, + "Connection": { + "ConnectionDelay": 1000, + "DelayAfterFirmwareUpdate": 1000, + "DtrEnable": true, + "EEPROMSize": 2048, + "ExtraConnectionRetry": false, + "ForceResetOnFirmwareUpdate": true, + "MessageSize": 90 + }, + "HardwareIds": ["^VID_303A&PID_1001"], + "Info": { + "CanInstallFirmware": true, + "CanResetBoard": true, + "FirmwareBaseName": "mobiflight_esp32s3", + "FirmwareExtension": "bin", + "FriendlyName": "ESP32-S3 DevKit", + "LatestFirmwareVersion": "0.0.1", + "MobiFlightType": "MobiFlight ESP32-S3", + "ResetFirmwareFile": "" + }, + "ModuleLimits": { + "MaxAnalogInputs": 6, + "MaxInputShifters": 6, + "MaxButtons": 32, + "MaxEncoders": 16, + "MaxLcdI2C": 2, + "MaxLedSegments": 8, + "MaxOutputs": 32, + "MaxServos": 8, + "MaxShifters": 6, + "MaxSteppers": 6, + "MaxInputMultiplexer": 6, + "MaxCustomDevices": 0 + }, + "Pins": [ + { "isAnalog": true, "isI2C": false, "isPWM": true, "Pin": 1 }, + { "isAnalog": true, "isI2C": false, "isPWM": true, "Pin": 2 }, + { "isAnalog": true, "isI2C": false, "isPWM": true, "Pin": 3 }, + { "isAnalog": true, "isI2C": false, "isPWM": true, "Pin": 4 }, + { "isAnalog": true, "isI2C": false, "isPWM": true, "Pin": 5 }, + { "isAnalog": true, "isI2C": false, "isPWM": true, "Pin": 6 }, + { "isAnalog": false, "isI2C": true, "isPWM": true, "Pin": 8 }, + { "isAnalog": false, "isI2C": true, "isPWM": true, "Pin": 9 }, + { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 10 }, + { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 11 }, + { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 12 }, + { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 13 }, + { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 14 }, + { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 15 }, + { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 16 }, + { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 17 }, + { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 18 }, + { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 19 }, + { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 20 }, + { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 21 } + ] +} diff --git a/copy_fw_files.py b/copy_fw_files.py index b900edcb..b22b6fd5 100644 --- a/copy_fw_files.py +++ b/copy_fw_files.py @@ -25,8 +25,12 @@ def copy_fw_files (source, target, env): if os.path.exists(build_path_json) == False: os.makedirs(build_path_json) + # Only convert bin to uf2 for Raspberry Pi Pico boards if fw_file_name[-3:] == "bin": - fw_file_name=fw_file_name[0:-3] + "uf2" + # Check if this is a Pico board by looking at the environment name + env_name = env.get('PIOENV', '') + if 'pico' in env_name.lower(): + fw_file_name=fw_file_name[0:-3] + "uf2" # Copy build FW file shutil.copy(fw_file_name, build_path_fw) diff --git a/platformio.ini b/platformio.ini index 53af38cf..cbab3cf0 100644 --- a/platformio.ini +++ b/platformio.ini @@ -187,3 +187,24 @@ lib_deps = monitor_speed = 115200 extra_scripts = ${env.extra_scripts} + +; Build settings for the ESP32-S3 +[env:mobiflight_esp32s3] +platform = espressif32 +board = heltec_wifi_lora_32_V3 +framework = arduino +build_flags = + ${env.build_flags} + '-DMOBIFLIGHT_TYPE="MobiFlight ESP32-S3"' + '-DMOBIFLIGHT_NAME="MobiFlight ESP32-S3"' + -DMEMLEN_CONFIG=2048 + -DMEMLEN_NAMES_BUFFER=1500 + -DMF_MAX_DEVICEMEM=2048 +build_src_filter = + ${env.build_src_filter} +lib_deps = + ${env.lib_deps} + ESP32Servo +monitor_speed = 115200 +extra_scripts = + ${env.extra_scripts} diff --git a/src/Config.cpp b/src/Config.cpp index b6cfae44..26d6e346 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -11,9 +11,14 @@ #include "Button.h" #include "Encoder.h" #include "Output.h" + #if !defined(ARDUINO_ARCH_AVR) +#if defined(ARDUINO_ARCH_ESP32) +#include +#else #include "ArduinoUniqueID.h" #endif +#endif #ifdef MF_ANALOG_SUPPORT #include "Analog.h" @@ -69,8 +74,11 @@ const uint8_t MEM_OFFSET_SERIAL = MEM_OFFSET_NAME + MEM_LEN_NAME; const uint8_t MEM_LEN_SERIAL = 11; const uint8_t MEM_OFFSET_CONFIG = MEM_OFFSET_NAME + MEM_LEN_NAME + MEM_LEN_SERIAL; +// Serial buffer for AVR and ESP32/other #ifdef ARDUINO_ARCH_AVR char serial[11]; // 3 characters for "SN-",7 characters for "xyz-zyx" plus terminating NULL +#elif defined(ARDUINO_ARCH_ESP32) +char serial[3 + 12 * 2 + 1]; // 3 for "SN-", 12 bytes MAC/ChipID as HEX, null term #else char serial[3 + UniqueIDsize * 2 + 1]; // 3 characters for "SN-", UniqueID as HEX String, terminating NULL #endif @@ -81,7 +89,7 @@ uint16_t configLengthEEPROM = 0; boolean configActivated = false; uint16_t pNameBuffer = 0; // pointer for nameBuffer during reading of config const uint16_t configLengthFlash = sizeof(CustomDeviceConfig); -bool boardReady = false; +bool boardReady = false; void resetConfig(); void readConfig(); @@ -518,10 +526,10 @@ void readConfigFromMemory(bool configFromFlash) #ifdef MF_ANALOG_SUPPORT case kTypeAnalogInputDeprecated: case kTypeAnalogInput: - params[0] = readUint(&addrMem, configFromFlash); // pin number - params[1] = readUint(&addrMem, configFromFlash); // sensitivity + params[0] = readUint(&addrMem, configFromFlash); // pin number + params[1] = readUint(&addrMem, configFromFlash); // sensitivity if (command == kTypeAnalogInputDeprecated) - Analog::Add(params[0], &nameBuffer[pNameBuffer], params[1], true); // MUST be before readName because readName returns the pointer for the NEXT Name + Analog::Add(params[0], &nameBuffer[pNameBuffer], params[1], true); // MUST be before readName because readName returns the pointer for the NEXT Name else Analog::Add(params[0], &nameBuffer[pNameBuffer], params[1], false); // MUST be before readName because readName returns the pointer for the NEXT Name copy_success = readName(&addrMem, nameBuffer, &pNameBuffer, configFromFlash); // copy the NULL terminated name to to nameBuffer and set to next free memory location @@ -679,6 +687,23 @@ void generateRandomSerial() #endif #if !defined(ARDUINO_ARCH_AVR) +#if defined(ARDUINO_ARCH_ESP32) +void readUniqueSerial() +{ + serial[0] = 'S'; + serial[1] = 'N'; + serial[2] = '-'; + uint8_t chipid[6]; + esp_efuse_mac_get_default(chipid); + for (int i = 0; i < 6; ++i) { + serial[3 + i * 2] = ((chipid[i] >> 4) & 0x0F) + 48; + if (serial[3 + i * 2] >= 58) serial[3 + i * 2] += 7; + serial[3 + i * 2 + 1] = (chipid[i] & 0x0F) + 48; + if (serial[3 + i * 2 + 1] >= 58) serial[3 + i * 2 + 1] += 7; + } + serial[3 + 6 * 2] = 0x00; +} +#else void readUniqueSerial() { serial[0] = 'S'; @@ -692,6 +717,7 @@ void readUniqueSerial() } } #endif +#endif void generateSerial(bool force) { diff --git a/src/MF_Analog/MFAnalog.cpp b/src/MF_Analog/MFAnalog.cpp index e4378cef..ebf915fd 100644 --- a/src/MF_Analog/MFAnalog.cpp +++ b/src/MF_Analog/MFAnalog.cpp @@ -18,6 +18,7 @@ void MFAnalog::attach(uint8_t pin, const char *name, uint8_t sensitivity, bool d _sensitivity = sensitivity; _pin = pin; _name = name; + // Special analog pin handling for some boards #ifdef ARDUINO_AVR_PROMICRO16 // ProMicro has a special pin assignment for analog pins // therefore reading from A6 and A7 does not work @@ -26,11 +27,13 @@ void MFAnalog::attach(uint8_t pin, const char *name, uint8_t sensitivity, bool d _pin = A6; else if (_pin == 6) _pin = A7; +#elif defined(ARDUINO_ARCH_ESP32) + // ESP32 analog pins are just numbers, but check for deprecated mapping if needed #endif // enabling PullUp makes a nonlinear behaviour if pot is used if (deprecated) pinMode(_pin, INPUT_PULLUP); - + // Fill averaging buffers with initial reading for (uint8_t i = 0; i < ADC_MAX_AVERAGE; i++) { readBuffer(); diff --git a/src/MF_Output/MFOutput.cpp b/src/MF_Output/MFOutput.cpp index 7010bb9b..e3f5afdb 100644 --- a/src/MF_Output/MFOutput.cpp +++ b/src/MF_Output/MFOutput.cpp @@ -14,8 +14,11 @@ MFOutput::MFOutput() void MFOutput::attach(uint8_t pin) { _pin = pin; -#ifdef ARDUINO_ARCH_RP2040 + // Use OUTPUT_12MA for RP2040, OUTPUT for others, allow override for ESP32 if needed +#if defined(ARDUINO_ARCH_RP2040) pinMode(_pin, OUTPUT_12MA); +#elif defined(ARDUINO_ARCH_ESP32) + pinMode(_pin, OUTPUT); #else pinMode(_pin, OUTPUT); #endif diff --git a/src/MF_Servo/MFServo.cpp b/src/MF_Servo/MFServo.cpp index 6a3bc040..e1499191 100644 --- a/src/MF_Servo/MFServo.cpp +++ b/src/MF_Servo/MFServo.cpp @@ -12,8 +12,10 @@ void MFServo::moveTo(int absolute) if (_targetPos != newValue) { _targetPos = newValue; if (!_initialized) { -#ifdef ARDUINO_ARCH_RP2040 +#if defined(ARDUINO_ARCH_RP2040) _servo.attach(_pin, 544, 2400); +#elif defined(ARDUINO_ARCH_ESP32) + _servo.attach(_pin, 500, 2500); // ESP32 typical servo pulse range #else _servo.attach(_pin); #endif diff --git a/src/MF_Servo/MFServo.h b/src/MF_Servo/MFServo.h index b17303ea..5bd0ff4a 100644 --- a/src/MF_Servo/MFServo.h +++ b/src/MF_Servo/MFServo.h @@ -7,7 +7,11 @@ #pragma once #include +#if defined(ESP32) || defined(ARDUINO_ARCH_ESP32) +#include +#else #include +#endif class MFServo { diff --git a/src/allocateMem.cpp b/src/allocateMem.cpp index e8e953fa..5a036fd4 100644 --- a/src/allocateMem.cpp +++ b/src/allocateMem.cpp @@ -7,7 +7,7 @@ #include "allocateMem.h" #include "commandmessenger.h" -#ifdef ARDUINO_ARCH_AVR +#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_ESP32) uint8_t deviceBuffer[MF_MAX_DEVICEMEM] = {0}; #else std::size_t deviceBuffer[MF_MAX_DEVICEMEM] = {0}; @@ -15,7 +15,8 @@ std::size_t deviceBuffer[MF_MAX_DEVICEMEM] = {0}; uint16_t nextPointer = 0; -#ifdef ARDUINO_ARCH_AVR +// For ESP32 and AVR, use uint8_t* for compatibility +#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_ESP32) uint8_t *allocateMemory(uint16_t size) #else std::size_t *allocateMemory(uint16_t size) diff --git a/src/allocateMem.h b/src/allocateMem.h index 19e89a51..700ac408 100644 --- a/src/allocateMem.h +++ b/src/allocateMem.h @@ -9,7 +9,7 @@ #include #include -#ifdef ARDUINO_ARCH_AVR +#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_ESP32) uint8_t *allocateMemory(uint16_t size); #else std::size_t *allocateMemory(uint16_t size); From b92630c736119240f43a22d96e826af2443a99cf Mon Sep 17 00:00:00 2001 From: "mia.metzler" Date: Sat, 20 Sep 2025 19:02:16 +0200 Subject: [PATCH 2/3] Add heltec wireless stick v3 as bsp --- _Boards/esp32s3.board.json | 46 ++++++++++++++++++++------------------ platformio.ini | 38 +++++++++++++++---------------- 2 files changed, 43 insertions(+), 41 deletions(-) diff --git a/_Boards/esp32s3.board.json b/_Boards/esp32s3.board.json index acff7dbe..eb42a401 100644 --- a/_Boards/esp32s3.board.json +++ b/_Boards/esp32s3.board.json @@ -16,23 +16,23 @@ "CanResetBoard": true, "FirmwareBaseName": "mobiflight_esp32s3", "FirmwareExtension": "bin", - "FriendlyName": "ESP32-S3 DevKit", + "FriendlyName": "Heltec Wireless Stick V3", "LatestFirmwareVersion": "0.0.1", "MobiFlightType": "MobiFlight ESP32-S3", "ResetFirmwareFile": "" }, "ModuleLimits": { - "MaxAnalogInputs": 6, - "MaxInputShifters": 6, - "MaxButtons": 32, - "MaxEncoders": 16, + "MaxAnalogInputs": 4, + "MaxInputShifters": 4, + "MaxButtons": 20, + "MaxEncoders": 10, "MaxLcdI2C": 2, - "MaxLedSegments": 8, - "MaxOutputs": 32, - "MaxServos": 8, - "MaxShifters": 6, - "MaxSteppers": 6, - "MaxInputMultiplexer": 6, + "MaxLedSegments": 6, + "MaxOutputs": 20, + "MaxServos": 6, + "MaxShifters": 4, + "MaxSteppers": 4, + "MaxInputMultiplexer": 4, "MaxCustomDevices": 0 }, "Pins": [ @@ -40,21 +40,23 @@ { "isAnalog": true, "isI2C": false, "isPWM": true, "Pin": 2 }, { "isAnalog": true, "isI2C": false, "isPWM": true, "Pin": 3 }, { "isAnalog": true, "isI2C": false, "isPWM": true, "Pin": 4 }, - { "isAnalog": true, "isI2C": false, "isPWM": true, "Pin": 5 }, - { "isAnalog": true, "isI2C": false, "isPWM": true, "Pin": 6 }, - { "isAnalog": false, "isI2C": true, "isPWM": true, "Pin": 8 }, - { "isAnalog": false, "isI2C": true, "isPWM": true, "Pin": 9 }, + { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 5 }, + { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 6 }, + { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 7 }, + { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 8 }, + { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 9 }, { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 10 }, { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 11 }, { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 12 }, { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 13 }, { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 14 }, - { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 15 }, - { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 16 }, - { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 17 }, - { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 18 }, - { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 19 }, - { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 20 }, - { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 21 } + { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 21 }, + { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 33 }, + { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 34 }, + { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 35 }, + { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 36 }, + { "isAnalog": false, "isI2C": false, "isPWM": true, "Pin": 37 }, + { "isAnalog": false, "isI2C": true, "isPWM": true, "Pin": 41 }, + { "isAnalog": false, "isI2C": true, "isPWM": true, "Pin": 42 } ] } diff --git a/platformio.ini b/platformio.ini index cbab3cf0..2cd193b5 100644 --- a/platformio.ini +++ b/platformio.ini @@ -18,9 +18,9 @@ ; Common build settings across all devices [env] -lib_deps = +lib_deps = waspinator/AccelStepper @ 1.61 - https://github.com/MobiFlight/LiquidCrystal_I2C#v1.1.5 + https://github.com/miathedev/LiquidCrystal_I2C.git#master https://github.com/MobiFlight/Arduino-CmdMessenger#4.2.2 custom_lib_deps_Atmel = arduino-libraries/Servo @ 1.1.8 @@ -70,7 +70,7 @@ extra_scripts = platform = atmelavr board = megaatmega2560 framework = arduino -build_flags = +build_flags = ${env.build_flags} '-DMOBIFLIGHT_TYPE="MobiFlight Mega"' '-DMOBIFLIGHT_NAME="MobiFlight Mega"' @@ -79,13 +79,13 @@ build_flags = -DMF_MAX_DEVICEMEM=1600 ; max. memory size for devices build_unflags = ;-DMF_STEPPER_SUPPORT ; this is just an example how to deactivate a device -build_src_filter = +build_src_filter = ${env.build_src_filter} -lib_deps = +lib_deps = ${env.lib_deps} ${env.custom_lib_deps_Atmel} monitor_speed = 115200 -extra_scripts = +extra_scripts = ${env.extra_scripts} ; Build settings for the Arduino Pro Micro @@ -93,7 +93,7 @@ extra_scripts = platform = atmelavr board = sparkfun_promicro16 framework = arduino -build_flags = +build_flags = ${env.build_flags} '-DMOBIFLIGHT_TYPE="MobiFlight Micro"' '-DMOBIFLIGHT_NAME="MobiFlight Micro"' @@ -102,13 +102,13 @@ build_flags = -DMF_MAX_DEVICEMEM=470 ; max. memory size for devices build_unflags = ;-DMF_STEPPER_SUPPORT ; this is just an example how to deactivate a device -build_src_filter = +build_src_filter = ${env.build_src_filter} -lib_deps = +lib_deps = ${env.lib_deps} ${env.custom_lib_deps_Atmel} monitor_speed = 115200 -extra_scripts = +extra_scripts = ${env.extra_scripts} @@ -117,7 +117,7 @@ extra_scripts = platform = atmelavr board = uno framework = arduino -build_flags = +build_flags = ${env.build_flags} '-DMOBIFLIGHT_TYPE="MobiFlight Uno"' '-DMOBIFLIGHT_NAME="MobiFlight Uno"' @@ -126,13 +126,13 @@ build_flags = -DMF_MAX_DEVICEMEM=420 ; max. memory size for devices build_unflags = ;-DMF_STEPPER_SUPPORT ; this is just an example how to deactivate a device -build_src_filter = +build_src_filter = ${env.build_src_filter} -lib_deps = +lib_deps = ${env.lib_deps} ${env.custom_lib_deps_Atmel} monitor_speed = 115200 -extra_scripts = +extra_scripts = ${env.extra_scripts} ; Build settings for the Arduino Nano @@ -140,7 +140,7 @@ extra_scripts = platform = atmelavr board = nanoatmega328 framework = arduino -build_flags = +build_flags = ${env.build_flags} '-DMOBIFLIGHT_TYPE="MobiFlight Nano"' '-DMOBIFLIGHT_NAME="MobiFlight Nano"' @@ -150,13 +150,13 @@ build_flags = -I./_Boards/Atmel/Board_Nano build_unflags = ;-DMF_STEPPER_SUPPORT ; this is just an example how to deactivate a device -build_src_filter = +build_src_filter = ${env.build_src_filter} lib_deps = ${env.lib_deps} ${env.custom_lib_deps_Atmel} monitor_speed = 115200 -extra_scripts = +extra_scripts = ${env.extra_scripts} ; Build settings for the Raspberry Pico original @@ -185,13 +185,13 @@ lib_deps = ${env.lib_deps} ${env.custom_lib_deps_Pico} monitor_speed = 115200 -extra_scripts = +extra_scripts = ${env.extra_scripts} ; Build settings for the ESP32-S3 [env:mobiflight_esp32s3] platform = espressif32 -board = heltec_wifi_lora_32_V3 +board = heltec_wireless_stick_v3 framework = arduino build_flags = ${env.build_flags} From ba5c79ba04ea0c00378e5be9a90fffe434f44829 Mon Sep 17 00:00:00 2001 From: "mia.metzler" Date: Sat, 20 Sep 2025 19:03:48 +0200 Subject: [PATCH 3/3] Revert wrong board --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 2cd193b5..2dea1c68 100644 --- a/platformio.ini +++ b/platformio.ini @@ -191,7 +191,7 @@ extra_scripts = ; Build settings for the ESP32-S3 [env:mobiflight_esp32s3] platform = espressif32 -board = heltec_wireless_stick_v3 +board = heltec_wifi_lora_32_V3 framework = arduino build_flags = ${env.build_flags}