From 67284f70c30050d34e13aef529a6c511e2951a85 Mon Sep 17 00:00:00 2001 From: Lutz Date: Sat, 10 Oct 2026 16:45:19 -0700 Subject: [PATCH 01/26] feat(build): add RP2040 board plumbing Board ID defines (2101/2201), pins-file selection arms, local-config arms, and validation gates for ARDUINO_ARCH_RP2040. Adds the [common_rp2xxx] platformio section (Earle Philhower core via the maxgerhardt platform wrapper) with rp2040_jackw01 and rp2040_skr_pico environments, and unignores Configuration_local_examples/. Co-Authored-By: Claude Code --- .gitignore | 2 ++ Configuration.hpp | 4 ++++ ConfigurationValidation.hpp | 12 ++++++----- Constants.hpp | 6 ++++++ LocalConfiguration.hpp | 4 ++++ platformio.ini | 40 +++++++++++++++++++++++++++++++++++++ 6 files changed, 63 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index a81693dc..b0686c2e 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,8 @@ CMakeListsPrivate.txt build_cache Configuration_local* +!Configuration_local_examples/ +!Configuration_local_examples/* MeadeToWikiOutput.txt # macOS diff --git a/Configuration.hpp b/Configuration.hpp index bebb8c7c..353208bd 100644 --- a/Configuration.hpp +++ b/Configuration.hpp @@ -273,6 +273,10 @@ #include "boards/AVR_MKS_GEN_L_V2/pins_MKS_GEN_L_V2.h" #elif (BOARD == BOARD_AVR_MKS_GEN_L_V21) #include "boards/AVR_MKS_GEN_L_V21/pins_MKS_GEN_L_V21.h" +#elif (BOARD == BOARD_RP2040_JACKW01) + #include "boards/RP2040_JACKW01/pins_RP2040_JACKW01.hpp" +#elif (BOARD == BOARD_RP2040_SKR_PICO) + #include "boards/RP2040_SKR_PICO/pins_RP2040_SKR_PICO.hpp" #endif #include "Configuration_adv.hpp" diff --git a/ConfigurationValidation.hpp b/ConfigurationValidation.hpp index eb31aedb..050c4ec3 100644 --- a/ConfigurationValidation.hpp +++ b/ConfigurationValidation.hpp @@ -17,7 +17,7 @@ #endif // Platform -#if defined(ESP32) || defined(__AVR_ATmega2560__) +#if defined(ESP32) || defined(__AVR_ATmega2560__) || defined(ARDUINO_ARCH_RP2040) // Valid platform #else #error Unsupported platform configuration. Use at own risk. @@ -30,6 +30,8 @@ && ((DISPLAY_TYPE == DISPLAY_TYPE_NONE) || (DISPLAY_TYPE == DISPLAY_TYPE_LCD_KEYPAD) || (DISPLAY_TYPE_LCD_KEYPAD_I2C_MCP23008) \ || (DISPLAY_TYPE_LCD_KEYPAD_I2C_MCP23017)) // Valid display for ATmega +#elif defined(ARDUINO_ARCH_RP2040) && (DISPLAY_TYPE == DISPLAY_TYPE_NONE) +// Valid display for RP2040 (no LCD menu display support yet) #else #error Unsupported display configuration. Use at own risk. #endif @@ -81,7 +83,7 @@ #else #error Defined an AZ driver, but no AZ stepper. #endif -#elif defined(__AVR_ATmega2560__) +#elif defined(__AVR_ATmega2560__) || defined(ARDUINO_ARCH_RP2040) // Azimuth configuration #if (AZ_DRIVER_TYPE == DRIVER_TYPE_TMC2209_UART) #ifndef AZ_DRIVER_ADDRESS @@ -102,7 +104,7 @@ #else #error Defined an ALT driver, but no ALT stepper. #endif -#elif defined(__AVR_ATmega2560__) +#elif defined(__AVR_ATmega2560__) || defined(ARDUINO_ARCH_RP2040) // Altitude configuration #if (ALT_DRIVER_TYPE == DRIVER_TYPE_TMC2209_UART) #ifndef ALT_DRIVER_ADDRESS @@ -166,8 +168,8 @@ // External sensors #if (USE_GPS == 0) // Baseline configuration without GPS is valid -#elif defined(ESP32) || defined(__AVR_ATmega2560__) -// GPS is supported on ESP32 and ATmega +#elif defined(ESP32) || defined(__AVR_ATmega2560__) || defined(ARDUINO_ARCH_RP2040) +// GPS is supported on ESP32, ATmega and RP2040 #else #error Unsupported GPS configuration. Use at own risk. #endif diff --git a/Constants.hpp b/Constants.hpp index e37811b2..c93cfd30 100644 --- a/Constants.hpp +++ b/Constants.hpp @@ -21,6 +21,12 @@ #define BOARD_ESP32_ESP32DEV 1001 #define BOARD_OAE_V1 1002 +// RP2040 based boards (2000-2999) +// 2101-2199: Pico family + JackW01 printer carrier board +// 2201-2299: BTT SKR Pico family +#define BOARD_RP2040_JACKW01 2101 +#define BOARD_RP2040_SKR_PICO 2201 + /** * Supported keypad/display types. Use one of these values for DISPLAY_TYPE configuration matching your used display and keypad. * diff --git a/LocalConfiguration.hpp b/LocalConfiguration.hpp index 14a00510..428fd3c7 100644 --- a/LocalConfiguration.hpp +++ b/LocalConfiguration.hpp @@ -18,6 +18,10 @@ #include "Configuration_local_esp32dev.hpp" #elif BOARD == BOARD_OAE_V1 && __has_include("Configuration_local_oae.hpp") #include "Configuration_local_oae.hpp" +#elif BOARD == BOARD_RP2040_JACKW01 && __has_include("Configuration_local_rp2040_jackw01.hpp") + #include "Configuration_local_rp2040_jackw01.hpp" +#elif BOARD == BOARD_RP2040_SKR_PICO && __has_include("Configuration_local_rp2040_skr_pico.hpp") + #include "Configuration_local_rp2040_skr_pico.hpp" #elif __has_include("Configuration_local.hpp") #include "Configuration_local.hpp" #endif \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 8afeb09a..6dce5f47 100644 --- a/platformio.ini +++ b/platformio.ini @@ -139,6 +139,46 @@ build_flags = -std=gnu++17 -D BOARD=BOARD_OAE_V1 -D ESP32BOARD +[common_rp2xxx] +extends = common_embedded +; Use the maxgerhardt platform wrapper to access the Earle Philhower arduino-pico core. +; The official platform-raspberrypi uses the Arduino-mbed core, which has poorer +; library compatibility and no flexible UART pin remapping. +platform = https://github.com/maxgerhardt/platform-raspberrypi.git +board_build.core = earlephilhower +lib_deps = + mikalhart/TinyGPSPlus @ ^1.0.2 + teemuatlut/TMCStepper @ ^0.7.1 + waspinator/AccelStepper @ ^1.61 +; SSD1306 info display support (SSD1306_128x64_Display.cpp is always compiled) + https://github.com/ClutchplateDude/esp8266-oled-ssd1306#4.6.2 +; TimerInterrupt is AVR-only (uses OCR1A etc.); RP2040 uses hardware/timer.h directly +lib_ignore = TimerInterrupt + +[env:rp2040_jackw01] +extends = common_rp2xxx +board = rpipico +build_flags = + ${env.build_flags} +; arduino-pico core deprecates the B00000000-style Arduino::Binary.h macros used throughout the shared Mount code + -Wno-deprecated-declarations +; The arduino-pico core headers and the SSD1306 OLED library trigger -Woverloaded-virtual +; (-Werror) when parsed together in the same TU; the warning never fires in OAT code itself. + -Wno-overloaded-virtual + -D BOARD=BOARD_RP2040_JACKW01 + +[env:rp2040_skr_pico] +extends = common_rp2xxx +board = rpipico +build_flags = + ${env.build_flags} +; arduino-pico core deprecates the B00000000-style Arduino::Binary.h macros used throughout the shared Mount code + -Wno-deprecated-declarations +; The arduino-pico core headers and the SSD1306 OLED library trigger -Woverloaded-virtual +; (-Werror) when parsed together in the same TU; the warning never fires in OAT code itself. + -Wno-overloaded-virtual + -D BOARD=BOARD_RP2040_SKR_PICO + [env:native] platform = native test_build_src = true From 4107efbde354e87385c03b64912f040f76498d0d Mon Sep 17 00:00:00 2001 From: Lutz Date: Sat, 10 Oct 2026 16:45:31 -0700 Subject: [PATCH 02/26] fix(config): define end-switch backslew constants unconditionally The RA/DEC END_SWITCH_ACTIVE_STATE and ENDSWITCH_BACKSLEW_DEG constants were only defined inside the '#else' of '#ifndef USE_*_END_SWITCH', i.e. only when that axis's end switches were enabled. EndSwitches.cpp references both axes' backslew constants whenever either feature is on, so a DEC-only (or RA-only) end switch configuration failed to compile on every platform. Co-Authored-By: Claude Code --- Configuration_adv.hpp | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/Configuration_adv.hpp b/Configuration_adv.hpp index 48d87f7f..c90e35b6 100644 --- a/Configuration_adv.hpp +++ b/Configuration_adv.hpp @@ -556,16 +556,15 @@ // Enable RA End Switches in your local configuration. Do not edit here! #ifndef USE_RA_END_SWITCH #define USE_RA_END_SWITCH 0 -#else - #ifndef RA_END_SWITCH_ACTIVE_STATE - #define RA_END_SWITCH_ACTIVE_STATE LOW - #endif - // You can define how many degrees to slew back after the end switch has triggered. - // Mechanical end switches might have a hysteresis behavior, meaning once signaled, - // it needs to move well back beyond the signal point to become un-signaled. - #ifndef RA_ENDSWITCH_BACKSLEW_DEG - #define RA_ENDSWITCH_BACKSLEW_DEG 0.5 - #endif +#endif +#ifndef RA_END_SWITCH_ACTIVE_STATE + #define RA_END_SWITCH_ACTIVE_STATE LOW +#endif +// You can define how many degrees to slew back after the end switch has triggered. +// Mechanical end switches might have a hysteresis behavior, meaning once signaled, +// it needs to move well back beyond the signal point to become un-signaled. +#ifndef RA_ENDSWITCH_BACKSLEW_DEG + #define RA_ENDSWITCH_BACKSLEW_DEG 0.5 #endif ////////////////////////////////////////// @@ -574,17 +573,15 @@ // Enable DEC End Switches in your local configuration. Do not edit here! #ifndef USE_DEC_END_SWITCH #define USE_DEC_END_SWITCH 0 -#else - #ifndef DEC_END_SWITCH_ACTIVE_STATE - #define DEC_END_SWITCH_ACTIVE_STATE LOW - #endif - // You can define how many degrees to slew back after the end switch has triggered. - // Mechanical end switches might have a hysteresis behavior, meaning once signaled, - // it needs to move well back beyond the signal point to become un-signaled. - #ifndef DEC_ENDSWITCH_BACKSLEW_DEG - #define DEC_ENDSWITCH_BACKSLEW_DEG 0.5 - #endif - +#endif +#ifndef DEC_END_SWITCH_ACTIVE_STATE + #define DEC_END_SWITCH_ACTIVE_STATE LOW +#endif +// You can define how many degrees to slew back after the end switch has triggered. +// Mechanical end switches might have a hysteresis behavior, meaning once signaled, +// it needs to move well back beyond the signal point to become un-signaled. +#ifndef DEC_ENDSWITCH_BACKSLEW_DEG + #define DEC_ENDSWITCH_BACKSLEW_DEG 0.5 #endif ////////////////////////////////////////// From ba77e38e20b5ac2346aa493248337f40db288671 Mon Sep 17 00:00:00 2001 From: Lutz Date: Sat, 10 Oct 2026 16:45:31 -0700 Subject: [PATCH 03/26] feat(rp2040): add platform runtime support - EPROMStore: flash-backed EEPROM section for the Philhower arduino-pico core (API-identical to the ESP32 path) - InterruptCallback: repeating hardware-alarm timer via the Pico SDK add_repeating_timer_us() API for the 2 kHz stepper control interrupt - b_setup: USB CDC flow-control bypass and connect wait, GPS/UART1 pin remapping, fan PWM, JackW01 shared-EN handling, and 115200 baud TMC serial on RP2040 (57600 kept on AVR/ESP32); AZ/ALT DIAG pinMode calls now guarded like RA/DEC (pins optional per board) - c_buttons/f_serial: explicit serial polling - the Philhower core does not reliably run serialEvent() for USB CDC - Mount: TMC2209 toff=4 on RP2040 only (toff>=3 required for StealthChop slow-decay phase); toff(1) unchanged on AVR/ESP32 - DayTime/Declination/Latitude/Longitude: defaulted copy assignments to silence -Wdeprecated-copy on the RP2040 toolchain - SSD1306_128x64_Display: wrap Arduino.h/SSD1306Wire.h includes in PUSH_NO_WARNINGS for the arduino-pico core headers Co-Authored-By: Claude Code --- src/EPROMStore.cpp | 35 ++++++++++++++ src/InterruptCallback.cpp | 47 +++++++++++++++++++ src/Latitude.hpp | 1 + src/Longitude.hpp | 1 + src/Mount.cpp | 40 ++++++++++++++++ src/SSD1306_128x64_Display.hpp | 4 ++ src/b_setup.hpp | 83 +++++++++++++++++++++++++++++++++- src/c_buttons.hpp | 7 +++ src/core/types/DayTime.hpp | 1 + src/core/types/Declination.hpp | 1 + src/core/types/Latitude.hpp | 1 + src/core/types/Longitude.hpp | 1 + src/f_serial.hpp | 2 +- 13 files changed, 221 insertions(+), 3 deletions(-) diff --git a/src/EPROMStore.cpp b/src/EPROMStore.cpp index 5784c177..b4c2108d 100644 --- a/src/EPROMStore.cpp +++ b/src/EPROMStore.cpp @@ -84,6 +84,41 @@ uint8_t EEPROMStore::read(uint8_t location) return value; } +#elif defined(ARDUINO_ARCH_RP2040) + +// Initialize the flash-backed EEPROM emulation provided by the Philhower +// arduino-pico core. API is identical to the ESP32 path. +void EEPROMStore::initialize() +{ + LOG(DEBUG_EEPROM, "[EEPROM]: RP2040: Startup with %d bytes", STORE_SIZE); + EEPROM.begin(STORE_SIZE); + + displayContents(); +} + +// Update the given location with the given value +void EEPROMStore::update(uint8_t location, uint8_t value) +{ + LOG(DEBUG_EEPROM, "[EEPROM]: RP2040: Writing %x to %d", value, location); + EEPROM.write(location, value); +} + +// Complete the transaction (flush RAM cache to flash) +void EEPROMStore::commit() +{ + LOG(DEBUG_EEPROM, "[EEPROM]: RP2040: Committing"); + EEPROM.commit(); +} + +// Read the value at the given location +uint8_t EEPROMStore::read(uint8_t location) +{ + uint8_t value; + value = EEPROM.read(location); + LOG(DEBUG_EEPROM, "[EEPROM]: RP2040: Read %x from %d", value, location); + return value; +} + #else // Initialize the EEPROM storage in a platform-independent abstraction diff --git a/src/InterruptCallback.cpp b/src/InterruptCallback.cpp index 2a7d5694..18ab6601 100644 --- a/src/InterruptCallback.cpp +++ b/src/InterruptCallback.cpp @@ -20,6 +20,11 @@ PUSH_NO_WARNINGS #include "libs/TimerInterrupt/TimerInterrupt.h" POP_NO_WARNINGS + #elif defined(ARDUINO_ARCH_RP2040) + // Earle Philhower arduino-pico core exposes the Pico SDK alarm API. + // add_repeating_timer_us() fires a hardware alarm callback at a precise + // interval without relying on FreeRTOS or a second core. + #include #else #error Unrecognized board selected. Either implement interrupt code or define the board here. #endif @@ -47,5 +52,47 @@ void InterruptCallback::start() ITimer2.restartTimer(); } + #elif defined(ARDUINO_ARCH_RP2040) + +// Storage for the repeating timer handle and the user callback+payload. +static repeating_timer_t _rp2040_timer; +static interrupt_callback_p _rp2040_callback = nullptr; +static void *_rp2040_payload = nullptr; + +// The Pico SDK alarm callback signature returns bool; returning true keeps +// the timer repeating. +static bool rp2040_timer_isr(repeating_timer_t * /* rt */) +{ + if (_rp2040_callback) + { + _rp2040_callback(_rp2040_payload); + } + return true; // Keep repeating +} + +bool InterruptCallback::setInterval(float intervalMs, interrupt_callback_p callback, void *payload) +{ + _rp2040_callback = callback; + _rp2040_payload = payload; + + // Positive delay_us means the period is measured from callback-start to + // callback-start (fixed wall-clock rate), which is what the stepper + // controller needs for consistent timing. + int32_t intervalUs = static_cast(intervalMs * 1000.0f); + return add_repeating_timer_us(intervalUs, rp2040_timer_isr, nullptr, &_rp2040_timer); +} + +void InterruptCallback::stop() +{ + cancel_repeating_timer(&_rp2040_timer); +} + +void InterruptCallback::start() +{ + // Re-arm with the same interval. The stored callback/payload are still set. + int32_t intervalUs = static_cast(_rp2040_timer.delay_us); + add_repeating_timer_us(intervalUs, rp2040_timer_isr, nullptr, &_rp2040_timer); +} + #endif #endif \ No newline at end of file diff --git a/src/Latitude.hpp b/src/Latitude.hpp index c3ec1591..a3d1f271 100644 --- a/src/Latitude.hpp +++ b/src/Latitude.hpp @@ -15,6 +15,7 @@ class Latitude : public core::Latitude { } Latitude(const Latitude &other); + Latitude &operator=(const Latitude &) = default; Latitude(int h, int m, int s); Latitude(float inDegrees); diff --git a/src/Longitude.hpp b/src/Longitude.hpp index 19661c7f..4c2bd0d0 100644 --- a/src/Longitude.hpp +++ b/src/Longitude.hpp @@ -17,6 +17,7 @@ class Longitude : public core::Longitude { } Longitude(const Longitude &other); + Longitude &operator=(const Longitude &) = default; Longitude(int h, int m, int s); Longitude(float inDegrees); diff --git a/src/Mount.cpp b/src/Mount.cpp index 22911649..d191bada 100644 --- a/src/Mount.cpp +++ b/src/Mount.cpp @@ -498,7 +498,11 @@ void Mount::configureRAdriver(Stream *serial, float rsense, byte driveraddress, _driverRA->rms_current(rmscurrent, 1.0f); //holdMultiplier = 1 to set ihold = irun _driverRA->pdn_disable(1); _driverRA->ihold(31); + #if defined(ARDUINO_ARCH_RP2040) + _driverRA->toff(4); // toff>=3 required for StealthChop slow-decay phase + #else _driverRA->toff(1); + #endif _driverRA->en_spreadCycle(RA_UART_STEALTH_MODE == 0); _driverRA->blank_time(24); _driverRA->microsteps(RA_TRACKING_MICROSTEPPING == 1 ? 0 : RA_TRACKING_MICROSTEPPING); // System starts in tracking mode @@ -537,7 +541,11 @@ void Mount::configureRAdriver(uint16_t RA_SW_RX, uint16_t RA_SW_TX, float rsense #endif LOG(DEBUG_STEPPERS, "[MOUNT]: Requested RA motor rms_current: %d mA", rmscurrent); _driverRA->rms_current(rmscurrent, 1.0f); //holdMultiplier = 1 to set ihold = irun + #if defined(ARDUINO_ARCH_RP2040) + _driverRA->toff(4); // toff>=3 required for StealthChop slow-decay phase + #else _driverRA->toff(1); + #endif _driverRA->en_spreadCycle(RA_UART_STEALTH_MODE == 0); _driverRA->blank_time(24); _driverRA->semin(0); //disable CoolStep so that current is consistent @@ -585,7 +593,11 @@ void Mount::configureDECdriver(Stream *serial, float rsense, byte driveraddress, _driverDEC->ihold(31); _driverDEC->iholddelay(15); _driverDEC->TPOWERDOWN(255); + #if defined(ARDUINO_ARCH_RP2040) + _driverDEC->toff(4); // toff>=3 required for StealthChop slow-decay phase + #else _driverDEC->toff(1); + #endif _driverDEC->en_spreadCycle(DEC_UART_STEALTH_MODE == 0); _driverDEC->blank_time(24); _driverDEC->microsteps( @@ -624,7 +636,11 @@ void Mount::configureDECdriver(uint16_t DEC_SW_RX, uint16_t DEC_SW_TX, float rse #endif LOG(DEBUG_STEPPERS, "[MOUNT]: Requested DEC motor rms_current: %d mA", rmscurrent); _driverDEC->rms_current(rmscurrent, 1.0f); //holdMultiplier = 1 to set ihold = irun + #if defined(ARDUINO_ARCH_RP2040) + _driverDEC->toff(4); // toff>=3 required for StealthChop slow-decay phase + #else _driverDEC->toff(1); + #endif _driverDEC->en_spreadCycle(DEC_UART_STEALTH_MODE == 0); _driverDEC->blank_time(24); _driverDEC->microsteps( @@ -668,7 +684,11 @@ void Mount::configureAZdriver(Stream *serial, float rsense, byte driveraddress, #endif LOG(DEBUG_STEPPERS, "[MOUNT]: Requested AZ motor rms_current: %d mA", rmscurrent); _driverAZ->rms_current(rmscurrent, AZ_MOTOR_HOLD_SETTING / 100.0); //holdMultiplier = 1 to set ihold = irun + #if defined(ARDUINO_ARCH_RP2040) + _driverAZ->toff(4); // toff>=3 required for StealthChop slow-decay phase + #else _driverAZ->toff(1); + #endif _driverAZ->en_spreadCycle(0); _driverAZ->blank_time(24); _driverAZ->microsteps(AZ_MICROSTEPPING == 1 ? 0 : AZ_MICROSTEPPING); // If 1 then disable microstepping @@ -706,7 +726,11 @@ void Mount::configureAZdriver(uint16_t AZ_SW_RX, uint16_t AZ_SW_TX, float rsense #endif LOG(DEBUG_STEPPERS, "[MOUNT]: Requested AZ motor rms_current: %d mA", rmscurrent); _driverAZ->rms_current(rmscurrent, AZ_MOTOR_HOLD_SETTING / 100.0); //holdMultiplier = 1 to set ihold = irun + #if defined(ARDUINO_ARCH_RP2040) + _driverAZ->toff(4); // toff>=3 required for StealthChop slow-decay phase + #else _driverAZ->toff(1); + #endif _driverAZ->en_spreadCycle(0); _driverAZ->blank_time(24); _driverAZ->microsteps(AZ_MICROSTEPPING == 1 ? 0 : AZ_MICROSTEPPING); // If 1 then disable microstepping @@ -749,7 +773,11 @@ void Mount::configureALTdriver(Stream *serial, float rsense, byte driveraddress, #endif LOG(DEBUG_STEPPERS, "[MOUNT]: Requested ALT motor rms_current: %d mA", rmscurrent); _driverALT->rms_current(rmscurrent, ALT_MOTOR_HOLD_SETTING / 100.0); //holdMultiplier = 1 to set ihold = irun + #if defined(ARDUINO_ARCH_RP2040) + _driverALT->toff(4); // toff>=3 required for StealthChop slow-decay phase + #else _driverALT->toff(1); + #endif _driverALT->en_spreadCycle(0); _driverALT->blank_time(24); _driverALT->microsteps(ALT_MICROSTEPPING == 1 ? 0 : ALT_MICROSTEPPING); // If 1 then disable microstepping @@ -787,7 +815,11 @@ void Mount::configureALTdriver(uint16_t ALT_SW_RX, uint16_t ALT_SW_TX, float rse #endif LOG(DEBUG_STEPPERS, "[MOUNT]: Requested ALT motor rms_current: %d mA", rmscurrent); _driverALT->rms_current(rmscurrent, ALT_MOTOR_HOLD_SETTING / 100.0); //holdMultiplier = 1 to set ihold = irun + #if defined(ARDUINO_ARCH_RP2040) + _driverALT->toff(4); // toff>=3 required for StealthChop slow-decay phase + #else _driverALT->toff(1); + #endif _driverALT->en_spreadCycle(0); _driverALT->blank_time(24); _driverALT->microsteps(ALT_MICROSTEPPING == 1 ? 0 : ALT_MICROSTEPPING); // If 1 then disable microstepping @@ -832,7 +864,11 @@ void Mount::configureFocusDriver(Stream *serial, float rsense, byte driveraddres #endif LOG(DEBUG_STEPPERS | DEBUG_FOCUS, "[FOCUS]: Requested Focus motor rms_current: %d mA", rmscurrent); _driverFocus->rms_current(rmscurrent, FOCUSER_MOTOR_HOLD_SETTING / 100.f); //holdMultiplier = 1 to set ihold = irun + #if defined(ARDUINO_ARCH_RP2040) + _driverFocus->toff(4); // toff>=3 required for StealthChop slow-decay phase + #else _driverFocus->toff(1); + #endif _driverFocus->en_spreadCycle(FOCUS_UART_STEALTH_MODE == 0); _driverFocus->blank_time(24); _driverFocus->microsteps(FOCUS_MICROSTEPPING == 1 ? 0 : FOCUS_MICROSTEPPING); // If 1 then disable microstepping @@ -878,7 +914,11 @@ void Mount::configureFocusDriver( #endif LOG(DEBUG_STEPPERS | DEBUG_FOCUS, "[FOCUS]: Requested Focus motor rms_current: %d mA", rmscurrent); _driverFocus->rms_current(rmscurrent, FOCUSER_MOTOR_HOLD_SETTING / 100.f); //holdMultiplier = 1 to set ihold = irun + #if defined(ARDUINO_ARCH_RP2040) + _driverFocus->toff(4); // toff>=3 required for StealthChop slow-decay phase + #else _driverFocus->toff(1); + #endif _driverFocus->en_spreadCycle(FOCUS_UART_STEALTH_MODE == 0); _driverFocus->blank_time(24); _driverFocus->microsteps(FOCUS_MICROSTEPPING == 1 ? 0 : FOCUS_MICROSTEPPING); // If 1 then disable microstepping diff --git a/src/SSD1306_128x64_Display.hpp b/src/SSD1306_128x64_Display.hpp index 32f14633..2cdea708 100644 --- a/src/SSD1306_128x64_Display.hpp +++ b/src/SSD1306_128x64_Display.hpp @@ -1,6 +1,10 @@ #pragma once +PUSH_NO_WARNINGS +// The arduino-pico core headers (the Arduino.h chain) and the OLED library are not +// warning-clean under our strict flag set (-Wshadow). #include #include "SSD1306Wire.h" +POP_NO_WARNINGS #include "Configuration.hpp" #include "Utility.hpp" #include "Version.h" diff --git a/src/b_setup.hpp b/src/b_setup.hpp index 76f10786..72d9fabc 100644 --- a/src/b_setup.hpp +++ b/src/b_setup.hpp @@ -126,9 +126,28 @@ void setup() #endif #else Serial.begin(SERIAL_BAUDRATE); + #if defined(ARDUINO_ARCH_RP2040) + // OATControl (and other apps using C# SerialPort) open the port with DTR=false. + // The Philhower USB CDC SerialUSB::write() gates TX on tud_cdc_connected() which + // requires DTR=true, so all responses are silently dropped for those hosts. + // ignoreFlowControl(true) bypasses the DTR check and always sends TX data. + Serial.ignoreFlowControl(true); + #endif #if DEBUG_LEVEL > 0 && DEBUG_SEPARATE_SERIAL == 1 DEBUG_SERIAL_PORT.begin(DEBUG_SERIAL_BAUDRATE); #endif + // RP2040 USB CDC: wait up to 3 s for the host to open the port so that + // LOG() calls below are not dropped (or do not block indefinitely). + // This only matters when DEBUG_LEVEL > 0 — in release builds LOG() is + // a no-op, so the wait is compiled out. + #if defined(ARDUINO_ARCH_RP2040) && DEBUG_LEVEL > 0 + { + uint32_t _cdcWaitStart = millis(); + while (!Serial && (millis() - _cdcWaitStart) < 3000UL) + { /* spin */ + } + } + #endif #endif #if TEST_VERIFY_MODE == 1 @@ -161,6 +180,10 @@ void setup() #if (INFO_DISPLAY_TYPE != INFO_DISPLAY_TYPE_NONE) int gpsLine = addConsoleText(F("Initialize GPS...")); #endif + #if defined(ARDUINO_ARCH_RP2040) && defined(RP2040_GPS_TX_PIN) && defined(RP2040_GPS_RX_PIN) + GPS_SERIAL_PORT.setTX(RP2040_GPS_TX_PIN); + GPS_SERIAL_PORT.setRX(RP2040_GPS_RX_PIN); + #endif GPS_SERIAL_PORT.begin(GPS_BAUD_RATE); #if (INFO_DISPLAY_TYPE != INFO_DISPLAY_TYPE_NONE) updateConsoleText(gpsLine, F("Initialize GPS... OK")); @@ -180,6 +203,11 @@ void setup() updateConsoleText(dewHeaterLine, F("Enable Dew Heater... OK")); #endif +#if defined(RP2040_FAN1_PIN) + pinMode(RP2040_FAN1_PIN, OUTPUT); + analogWrite(RP2040_FAN1_PIN, (RP2040_FAN1_POWER_PERCENT * 255) / 100); +#endif + #if (USE_RA_END_SWITCH == 1 || USE_DEC_END_SWITCH == 1) int endSwitchesLine = addConsoleText(F("Init End Switches...")); LOG(DEBUG_ANY, "[SYSTEM]: Init EndSwitches..."); @@ -187,6 +215,18 @@ void setup() updateConsoleText(endSwitchesLine, F("Init End Switches... OK")); #endif + ///////////////////////////////// + // RP2040: UART pin remapping + ///////////////////////////////// + // RP2040_UART1_TX_PIN / RP2040_UART1_RX_PIN are defined in the board's + // pins file only for RP2040 targets that use a non-default UART1 mapping. +#if defined(ARDUINO_ARCH_RP2040) && defined(RP2040_UART1_TX_PIN) && defined(RP2040_UART1_RX_PIN) + Serial2.setTX(RP2040_UART1_TX_PIN); + Serial2.setRX(RP2040_UART1_RX_PIN); + Serial2.setPollingMode(true); // Must be called before begin(); avoids IRQ/CoreMutex blocking in TMCStepper read path + Serial2.begin(115200); // TMCStepper HW-serial path never calls begin(); must do it here. +#endif + ///////////////////////////////// // Microstepping/driver pins ///////////////////////////////// @@ -215,6 +255,8 @@ void setup() #ifdef RA_SERIAL_PORT #ifdef OAE RA_SERIAL_PORT.begin(57600, SERIAL_8N1, RA_RX_PIN, RA_TX_PIN); + #elif defined(ARDUINO_ARCH_RP2040) + RA_SERIAL_PORT.begin(115200); // TMCStepper requires 115200 baud on RP2040 #else RA_SERIAL_PORT.begin(57600); // Start HardwareSerial comms with driver #endif @@ -248,6 +290,8 @@ void setup() #ifdef DEC_SERIAL_PORT #ifdef OAE DEC_SERIAL_PORT.begin(57600, SERIAL_8N1, DEC_RX_PIN, DEC_TX_PIN); + #elif defined(ARDUINO_ARCH_RP2040) + DEC_SERIAL_PORT.begin(115200); // TMCStepper requires 115200 baud on RP2040 #else DEC_SERIAL_PORT.begin(57600); // Start HardwareSerial comms with driver #endif @@ -262,10 +306,16 @@ void setup() pinMode(AZ_EN_PIN, OUTPUT); digitalWrite(AZ_EN_PIN, HIGH); // Logic HIGH to disable the driver initally #if AZ_DRIVER_TYPE == DRIVER_TYPE_TMC2209_UART - // include TMC2209 UART pins + // include TMC2209 UART pins + #if defined(AZ_DIAG_PIN) pinMode(AZ_DIAG_PIN, INPUT); + #endif #ifdef AZ_SERIAL_PORT + #if defined(ARDUINO_ARCH_RP2040) + AZ_SERIAL_PORT.begin(115200); // TMCStepper requires 115200 baud on RP2040 + #else AZ_SERIAL_PORT.begin(57600); // Start HardwareSerial comms with driver + #endif #endif #endif updateConsoleText(azLine, F("Init AZ axis... OK")); @@ -277,10 +327,16 @@ void setup() pinMode(ALT_EN_PIN, OUTPUT); digitalWrite(ALT_EN_PIN, HIGH); // Logic HIGH to disable the driver initally #if ALT_DRIVER_TYPE == DRIVER_TYPE_TMC2209_UART - // include TMC2209 UART pins + // include TMC2209 UART pins + #if defined(ALT_DIAG_PIN) pinMode(ALT_DIAG_PIN, INPUT); + #endif #ifdef ALT_SERIAL_PORT + #if defined(ARDUINO_ARCH_RP2040) + ALT_SERIAL_PORT.begin(115200); // TMCStepper requires 115200 baud on RP2040 + #else ALT_SERIAL_PORT.begin(57600); // Start HardwareSerial comms with driver + #endif #endif #endif updateConsoleText(altLine, F("Init ALT axis... OK")); @@ -295,11 +351,25 @@ void setup() // include TMC2209 UART pins #ifdef FOCUS_SERIAL_PORT LOG(DEBUG_FOCUS, "[FOCUS]: setup(): focus TMC2209U starting comms"); + #if defined(ARDUINO_ARCH_RP2040) + FOCUS_SERIAL_PORT.begin(115200); // TMCStepper requires 115200 baud on RP2040 + #else FOCUS_SERIAL_PORT.begin(57600); // Start HardwareSerial comms with driver + #endif #endif #endif updateConsoleText(focusLine, F("Init Focuser... OK")); #endif + +#if defined(RP2040_SHARED_EN_PIN) + // On boards where all stepper EN lines share one GPIO (e.g. JackW01 carrier), + // the per-axis init sequence leaves that GPIO HIGH (logic disabled) after the + // AZ/ALT blocks run. Force it LOW here so every driver is enabled once all + // UART addresses have been configured. Per-axis power management is handled + // via the TMC2209 IHOLD register over UART rather than toggling this pin. + pinMode(RP2040_SHARED_EN_PIN, OUTPUT); + digitalWrite(RP2040_SHARED_EN_PIN, LOW); +#endif // end microstepping ------------------- #if USE_HALL_SENSOR_RA_AUTOHOME == 1 || USE_HALL_SENSOR_DEC_AUTOHOME == 1 @@ -535,6 +605,15 @@ void setup() #endif #endif +#if defined(RP2040_SHARED_EN_PIN) + // Re-assert EN LOW after all driver configs. Each configureXXXdriver() that + // fails its UART connection test calls digitalWrite(X_EN_PIN, HIGH) as a + // safety measure; on JackW01 all EN lines share one GPIO so all four failures + // leave that GPIO HIGH (motors disabled). Override it here unconditionally so + // the motors are always enabled after initialization. + digitalWrite(RP2040_SHARED_EN_PIN, LOW); +#endif + LOG(DEBUG_ANY, "[SYSTEM]: Energize Steppers... OK"); updateConsoleText(stepperLine, F("Energize Steppers... OK")); diff --git a/src/c_buttons.hpp b/src/c_buttons.hpp index d594cb2c..c1c3a321 100644 --- a/src/c_buttons.hpp +++ b/src/c_buttons.hpp @@ -98,6 +98,13 @@ void loop() lcdMenu.setCursor(0, 1); #if SUPPORT_SERIAL_CONTROL == 1 + #if defined(ARDUINO_ARCH_RP2040) + // On RP2040, the Philhower core does not reliably call serialEvent() for the + // USB CDC Serial port when a host application opens the port and immediately + // sends data (e.g. OATControl). Poll explicitly on every loop() iteration so + // that commands are always processed regardless of inSerialControl state. + processSerialData(); + #endif if (inSerialControl) { if (lcdButtons.keyChanged(&lcd_key)) diff --git a/src/core/types/DayTime.hpp b/src/core/types/DayTime.hpp index 98c0638d..7ab5c3ca 100644 --- a/src/core/types/DayTime.hpp +++ b/src/core/types/DayTime.hpp @@ -18,6 +18,7 @@ class DayTime DayTime(); DayTime(const DayTime &other); + DayTime &operator=(const DayTime &) = default; DayTime(int h, int m, int s); // From hours (fractional) diff --git a/src/core/types/Declination.hpp b/src/core/types/Declination.hpp index de65d3e9..ca3185d5 100644 --- a/src/core/types/Declination.hpp +++ b/src/core/types/Declination.hpp @@ -15,6 +15,7 @@ class Declination : public DayTime public: Declination(); Declination(const Declination &other); + Declination &operator=(const Declination &) = default; Declination(int h, int m, int s); Declination(float inDegrees); diff --git a/src/core/types/Latitude.hpp b/src/core/types/Latitude.hpp index 168587ce..feb382b5 100644 --- a/src/core/types/Latitude.hpp +++ b/src/core/types/Latitude.hpp @@ -12,6 +12,7 @@ class Latitude : public DayTime public: Latitude(); Latitude(const Latitude &other); + Latitude &operator=(const Latitude &) = default; Latitude(int h, int m, int s); Latitude(float inDegrees); diff --git a/src/core/types/Longitude.hpp b/src/core/types/Longitude.hpp index 6c52e44e..f9722c1c 100644 --- a/src/core/types/Longitude.hpp +++ b/src/core/types/Longitude.hpp @@ -12,6 +12,7 @@ class Longitude : public DayTime public: Longitude(); Longitude(const Longitude &other); + Longitude &operator=(const Longitude &) = default; Longitude(int h, int m, int s); Longitude(float inDegrees); diff --git a/src/f_serial.hpp b/src/f_serial.hpp index 7f8458a1..7fe9d624 100644 --- a/src/f_serial.hpp +++ b/src/f_serial.hpp @@ -19,7 +19,7 @@ void serialLoop() mount.loop(); mount.displayStepperPositionThrottled(); - #ifdef ESP32 + #if defined(ESP32) || defined(ARDUINO_ARCH_RP2040) processSerialData(); #endif From 850a4b942b8a1c9b7dbd0688966b468cc515aa5a Mon Sep 17 00:00:00 2001 From: Lutz Date: Sat, 10 Oct 2026 16:45:43 -0700 Subject: [PATCH 04/26] feat(rp2040): add JackW01 and SKR Pico boards Pin definitions for the JackW01 Pi Pico printer carrier board and the BigTreeTech SKR Pico v1.0 (Klipper-derived mappings, TMC2209 UART address strapping documented per slot), plus a tracked example local configuration for the SKR Pico. Ported from PR #298 (EricSchubert); the orphaned bare-Pico pins file from that PR is intentionally not carried over. Co-Authored-By: Claude Code --- .../Configuration_local_rp2040_skr_pico.hpp | 154 +++++++++++++++++ boards/RP2040_JACKW01/pins_RP2040_JACKW01.hpp | 141 +++++++++++++++ .../RP2040_SKR_PICO/pins_RP2040_SKR_PICO.hpp | 163 ++++++++++++++++++ 3 files changed, 458 insertions(+) create mode 100644 Configuration_local_examples/Configuration_local_rp2040_skr_pico.hpp create mode 100644 boards/RP2040_JACKW01/pins_RP2040_JACKW01.hpp create mode 100644 boards/RP2040_SKR_PICO/pins_RP2040_SKR_PICO.hpp diff --git a/Configuration_local_examples/Configuration_local_rp2040_skr_pico.hpp b/Configuration_local_examples/Configuration_local_rp2040_skr_pico.hpp new file mode 100644 index 00000000..a757cfe5 --- /dev/null +++ b/Configuration_local_examples/Configuration_local_rp2040_skr_pico.hpp @@ -0,0 +1,154 @@ +/** + * @brief Local hardware configuration for a Raspberry Pi Pico (RP2040) + * on the BigTreeTech SKR Pico v1.0 printer controller board. + * + * This file is NOT tracked by Git and will survive branch changes. + * It is automatically included by LocalConfiguration.hpp when + * BOARD == BOARD_RP2040_SKR_PICO. + * + * Hardware summary + * ---------------- + * MCU : RP2040 (Raspberry Pi Pico) + * Board : BTT SKR Pico v1.0 + * Stepper slot : X -> RA (TMC2209, UART addr 0) + * Stepper slot : Y -> DEC (TMC2209, UART addr 2) + * Stepper slot : Z -> AZ (TMC2209, UART addr 1) + * Stepper slot : E0 -> ALT (TMC2209, UART addr 3) + * Motor rating : 0.9 deg / step (400 SPR), 470 mA + * Pulley : 16T aluminium GT2 + * RA homing : Hall sensor on GPIO4 (X-STOP / RA_DIAG_PIN) + * + * All pin assignments are in boards/RP2040_SKR_PICO/pins_RP2040_SKR_PICO.hpp. + * R_SENSE (0.11 ohm) is set globally in src/a_inits.hpp for all TMC2209_UART + * builds and does not need to be repeated here. + * + * Key difference from JackW01: each stepper driver has its own EN pin. + * AZ_ALWAYS_ON and ALT_ALWAYS_ON are NOT required on this board. + */ +#pragma once + +// ── Board ───────────────────────────────────────────────────────────────────── +#define BOARD BOARD_RP2040_SKR_PICO + +// ── Hemisphere ──────────────────────────────────────────────────────────────── +#define NORTHERN_HEMISPHERE 1 + +// ── Display (none) ──────────────────────────────────────────────────────────── +#define DISPLAY_TYPE DISPLAY_TYPE_NONE +#define INFO_DISPLAY_TYPE INFO_DISPLAY_TYPE_NONE + +// ── Stepper motor types ─────────────────────────────────────────────────────── +#define RA_STEPPER_TYPE STEPPER_TYPE_ENABLED +#define DEC_STEPPER_TYPE STEPPER_TYPE_ENABLED +#define AZ_STEPPER_TYPE STEPPER_TYPE_ENABLED +#define ALT_STEPPER_TYPE STEPPER_TYPE_ENABLED + +// ── Stepper driver types ────────────────────────────────────────────────────── +#define RA_DRIVER_TYPE DRIVER_TYPE_TMC2209_UART +#define DEC_DRIVER_TYPE DRIVER_TYPE_TMC2209_UART +#define AZ_DRIVER_TYPE DRIVER_TYPE_TMC2209_UART +#define ALT_DRIVER_TYPE DRIVER_TYPE_TMC2209_UART + +// ── Steps per revolution (0.9 deg motor = 400 full steps/rev) ───────────────── +#define RA_STEPPER_SPR 400 +#define DEC_STEPPER_SPR 400 +#define AZ_STEPPER_SPR 400 +#define ALT_STEPPER_SPR 400 + +// ── Pulley tooth count (16T aluminium GT2) ──────────────────────────────────── +#define RA_PULLEY_TEETH 16 +#define DEC_PULLEY_TEETH 16 +#define AZ_PULLEY_TEETH 16 +#define ALT_PULLEY_TEETH 16 + +// ── Microstepping ───────────────────────────────────────────────────────────── +// TMC2209 UART mode can switch microstepping dynamically at runtime. +// RA switches between slew (8×) and fine tracking (256×). +// DEC switches between slew (16×) and fine guiding (256×). +// AZ and ALT use a fixed microstepping mode (no dynamic switching). +#define RA_SLEW_MICROSTEPPING 8 // µsteps used while slewing RA +#define RA_TRACKING_MICROSTEPPING 256 // µsteps used for sidereal tracking +#define DEC_SLEW_MICROSTEPPING 16 // µsteps used while slewing DEC +#define DEC_GUIDE_MICROSTEPPING 256 // µsteps used for guide pulses +#define AZ_MICROSTEPPING 64 +#define ALT_MICROSTEPPING 4 + +// ── Motor direction ─────────────────────────────────────────────────────────── +// Set to 1 to reverse the direction of an axis if it moves the wrong way. +// Verify with manual move commands: :Mw#/:Me# (RA), :Mn#/:Ms# (DEC), +// :MAL#/:MAR# (AZ), :MAU#/:MAD# (ALT). Then set the appropriate flag to 1. +#define RA_INVERT_DIR 0 +#define DEC_INVERT_DIR 1 +#define AZ_INVERT_DIR 0 +#define ALT_INVERT_DIR 0 + +// ── StealthChop (silent mode) ───────────────────────────────────────────────── +// Configuration_adv.hpp defaults both to 0 (SpreadCycle = noisy). +// Set to 1 to enable StealthChop (silent) for RA tracking and DEC moves. +#define RA_UART_STEALTH_MODE 1 +#define DEC_UART_STEALTH_MODE 1 + +// ── Motor current ───────────────────────────────────────────────────────────── +// Motors are rated at 470 mA. Run at 75 % of rated current to reduce heat +// while maintaining adequate torque. RMS current is computed automatically: +// RMSCURRENT = RATING * (SETTING / 100) / sqrt(2) => ~249 mA RMS +// Do NOT define XXX_RMSCURRENT directly; Configuration_adv.hpp will error. +#define RA_MOTOR_CURRENT_RATING 470 // mA +#define RA_OPERATING_CURRENT_SETTING 75 // % + +#define DEC_MOTOR_CURRENT_RATING 470 // mA +#define DEC_OPERATING_CURRENT_SETTING 75 // % + +#define AZ_MOTOR_CURRENT_RATING 470 // mA +#define AZ_OPERATING_CURRENT_SETTING 75 // % + +#define ALT_MOTOR_CURRENT_RATING 470 // mA +#define ALT_OPERATING_CURRENT_SETTING 75 // % + +// ── AZ/ALT hold current ─────────────────────────────────────────────────────── +// AZ must hold position against backlash forces; use 40 % of run current. +// ALT is held by friction and gearing; bleed hold current to zero. +// These are percentages (0-100) converted to TMC2209 IHOLD by the firmware. +#define AZ_MOTOR_HOLD_SETTING 40 // % +#define ALT_MOTOR_HOLD_SETTING 0 // % + +// ── DEC axis travel limits ──────────────────────────────────────────────────── +// Physical limits measured from the home (level) position. +// These must be defined here; Configuration_adv.hpp defaults to 0.0f for +// non-OAM builds, which makes :Mn#/:Ms# target position 0 and do nothing. +#ifndef DEC_LIMIT_UP + #define DEC_LIMIT_UP 135.0f // 135° north of home +#endif +#ifndef DEC_LIMIT_DOWN + #define DEC_LIMIT_DOWN 35.0f // 35° south of home +#endif + +// ── RA Hall sensor auto-home ────────────────────────────────────────────────── +// Hall sensor is wired to GPIO4 (X-STOP input / RA_DIAG_PIN on SKR Pico). +// Active state LOW: sensor pulls GPIO4 LOW when the magnet is present. +// Search distance: 30° default (RA_HOMING_SENSOR_SEARCH_DEGREES in Configuration_adv.hpp). +// GPIO4 is configured INPUT (no pull-up); add external 10kΩ to 3.3V if sensor +// is open-drain, or change to INPUT_PULLUP in b_setup.hpp. +#define USE_HALL_SENSOR_RA_AUTOHOME 1 +#define RA_HOMING_SENSOR_PIN 4 // GPIO4 = RA_DIAG_PIN (X-STOP) +#define RA_HOMING_SENSOR_ACTIVE_STATE LOW // sensor pulls LOW when active + +// ── GPS ─────────────────────────────────────────────────────────────────────── +// ATGM336H-5N wired to left-side header: GPS TX→IO1, GPS RX→IO0, VCC→5V, GND. +// GPS_SERIAL_PORT, RP2040_GPS_TX_PIN, RP2040_GPS_RX_PIN defined in pins file. +// GPS_BAUD_RATE defaults to 9600 in Configuration_adv.hpp (matches module default). +#define USE_GPS 1 + +// ── FAN ─────────────────────────────────────────────────────────────────────── +// FAN1 power level as a percentage (0 = off, 100 = full speed). +// The pin and PWM are defined in pins_RP2040_SKR_PICO.hpp. +#define RP2040_FAN1_POWER_PERCENT 60 + +// Track immediately after boot +#define TRACK_ON_BOOT 0 + +// Uncomment to override defaults for stepper speeds and accelerations +//#define RA_STEPPER_SPEED 1200 // You can change the speed and acceleration of the steppers here. Max. Speed = 3000. +//#define RA_STEPPER_ACCELERATION 6000 +//#define DEC_STEPPER_SPEED 1300 // You can change the speed and acceleration of the steppers here. Max. Speed = 3000. +//#define DEC_STEPPER_ACCELERATION 6000 diff --git a/boards/RP2040_JACKW01/pins_RP2040_JACKW01.hpp b/boards/RP2040_JACKW01/pins_RP2040_JACKW01.hpp new file mode 100644 index 00000000..a467647b --- /dev/null +++ b/boards/RP2040_JACKW01/pins_RP2040_JACKW01.hpp @@ -0,0 +1,141 @@ +/** + * @brief Pin configuration for a Raspberry Pi Pico (RP2040/RP2350) mounted on + * the JackW01 pi-pico-printer-board carrier (https://github.com/jackw01/pi-pico-printer-board). + * + * Stepper slot mapping: + * X slot -> RA (TMC2209 UART address 0) + * Y slot -> DEC (TMC2209 UART address 1) + * Z slot -> AZ (TMC2209 UART address 2) + * E slot -> ALT (TMC2209 UART address 3) + * + * All four stepper enable lines are tied together to a single GPIO on this + * board (GPIO5). Define every axis EN pin to the same value so the firmware + * compiles cleanly; in practice enabling/disabling one axis affects all. + * Per-axis power management should be handled via the TMC2209 IHOLD register + * over UART rather than toggling EN. + * + * TMC2209 UART: all four drivers share a single-wire bus on UART1. + * TX -> GPIO8 (UART1 TX) + * RX -> GPIO9 (UART1 RX) + * Pin remapping must be applied before Serial2.begin() in platform setup: + * Serial2.setTX(RP2040_UART1_TX_PIN); + * Serial2.setRX(RP2040_UART1_RX_PIN); + */ + +#pragma once + +// ── RA axis (X slot, TMC2209 address 0) ────────────────────────────────────── +#ifndef RA_STEP_PIN + #define RA_STEP_PIN 7 +#endif +#ifndef RA_DIR_PIN + #define RA_DIR_PIN 6 +#endif +#ifndef RA_EN_PIN + #define RA_EN_PIN 5 // Shared with all axes on this board +#endif +#ifndef RA_DIAG_PIN + #define RA_DIAG_PIN 4 // X endstop input - used for Hall sensor RA homing +#endif + +// RA TMC2209 UART +#ifndef RA_SERIAL_PORT + #define RA_SERIAL_PORT Serial2 // UART1 via Philhower Serial2 +#endif +#ifndef RA_DRIVER_ADDRESS + #define RA_DRIVER_ADDRESS 0b00 // MS1=LOW, MS2=LOW +#endif + +// ── DEC axis (Y slot, TMC2209 address 2) ───────────────────────────────────── +#ifndef DEC_STEP_PIN + #define DEC_STEP_PIN 11 +#endif +#ifndef DEC_DIR_PIN + #define DEC_DIR_PIN 10 +#endif +#ifndef DEC_EN_PIN + #define DEC_EN_PIN 5 // Shared with all axes on this board +#endif +#ifndef DEC_DIAG_PIN + #define DEC_DIAG_PIN 3 // Y endstop input +#endif + +// DEC TMC2209 UART +#ifndef DEC_SERIAL_PORT + #define DEC_SERIAL_PORT Serial2 // Shared UART1 bus +#endif +#ifndef DEC_DRIVER_ADDRESS + #define DEC_DRIVER_ADDRESS 0b01 // MS1=HIGH, MS2=LOW -> address 1 +#endif + +// ── AZ axis (Z slot, TMC2209 address 1) ────────────────────────────────────── +#ifndef AZ_STEP_PIN + #define AZ_STEP_PIN 13 +#endif +#ifndef AZ_DIR_PIN + #define AZ_DIR_PIN 12 +#endif +#ifndef AZ_EN_PIN + #define AZ_EN_PIN 5 // Shared with all axes on this board +#endif + +// AZ TMC2209 UART +#ifndef AZ_SERIAL_PORT + #define AZ_SERIAL_PORT Serial2 // Shared UART1 bus +#endif +#ifndef AZ_DRIVER_ADDRESS + #define AZ_DRIVER_ADDRESS 0b10 // MS1=LOW, MS2=HIGH -> address 2 +#endif + +// ── ALT axis (Extruder slot, TMC2209 address 3) ─────────────────────────────── +#ifndef ALT_STEP_PIN + #define ALT_STEP_PIN 15 +#endif +#ifndef ALT_DIR_PIN + #define ALT_DIR_PIN 14 +#endif +#ifndef ALT_EN_PIN + #define ALT_EN_PIN 5 // Shared with all axes on this board +#endif + +// ALT TMC2209 UART +#ifndef ALT_SERIAL_PORT + #define ALT_SERIAL_PORT Serial2 // Shared UART1 bus +#endif +#ifndef ALT_DRIVER_ADDRESS + #define ALT_DRIVER_ADDRESS 0b11 // MS1=HIGH, MS2=HIGH -> address 3 +#endif + +// ── UART1 physical pin assignments ─────────────────────────────────────────── +// The JackW01 board routes UART to the TMC2209 drivers as follows: +// GPIO8 → R202 (1kΩ) → RESET/TX pad (UART1 TX) +// GPIO9 → R201 (100Ω) → MS3/RX pad (UART1 RX) +// +// BigTreeTech TMC2209 modules have an onboard resistor bridging their +// RESET/TX and MS3/RX pads to PDN_UART, so both JackW01 lines reach +// the TMC2209 PDN_UART pin. Standard two-wire hardware UART1 is used: +// TX: GPIO8 (native UART1 TX mux function) +// RX: GPIO9 (native UART1 RX mux function) +// +// b_setup.hpp calls Serial2.setTX()/setRX() before Serial2.begin() to +// remap UART1 to these pins. +#ifndef RP2040_UART1_TX_PIN + #define RP2040_UART1_TX_PIN 8 +#endif +#ifndef RP2040_UART1_RX_PIN + #define RP2040_UART1_RX_PIN 9 +#endif + +// All drivers use hardware UART (Serial2). +#define SW_SERIAL_UART 0 + +// ── Shared EN pin override ──────────────────────────────────────────────────── +// All four TMC2209 EN lines are wired together to GPIO5 on this board. +// After per-axis init leaves GPIO5 in an indeterminate state, b_setup.hpp will +// drive RP2040_SHARED_EN_PIN LOW once to enable all drivers together. +#define RP2040_SHARED_EN_PIN 5 + +// ── Debug serial port ───────────────────────────────────────────────────────── +#ifndef DEBUG_SERIAL_PORT + #define DEBUG_SERIAL_PORT Serial // USB CDC serial via Philhower core +#endif diff --git a/boards/RP2040_SKR_PICO/pins_RP2040_SKR_PICO.hpp b/boards/RP2040_SKR_PICO/pins_RP2040_SKR_PICO.hpp new file mode 100644 index 00000000..0f8c835a --- /dev/null +++ b/boards/RP2040_SKR_PICO/pins_RP2040_SKR_PICO.hpp @@ -0,0 +1,163 @@ +/** + * @brief Pin configuration for a Raspberry Pi Pico (RP2040) on the + * BigTreeTech SKR Pico v1.0 printer controller board. + * + * Hardware reference: https://github.com/bigtreetech/SKR-Pico + * Authoritative pin source: Klipper/SKR Pico klipper.cfg + * + * Stepper slot mapping (OAT axis -> board slot -> TMC2209 UART address): + * X slot -> RA (TMC2209 UART address 0) + * Y slot -> DEC (TMC2209 UART address 2) + * Z slot -> AZ (TMC2209 UART address 1) + * E0 slot -> ALT (TMC2209 UART address 3) + * + * Note: DEC uses address 2 and AZ uses address 1 — the opposite of the + * JackW01 board. This reflects the MS1/MS2 resistor strapping on + * the SKR Pico PCB. + * + * Each stepper driver has its own dedicated EN pin (unlike the JackW01 + * board where all EN lines share a single GPIO). No RP2040_SHARED_EN_PIN + * is needed; AZ_ALWAYS_ON / ALT_ALWAYS_ON are not required. + * + * TMC2209 UART: all four drivers share a two-wire bus on UART1. + * TX -> GPIO8 (UART1 TX, same physical assignment as JackW01) + * RX -> GPIO9 (UART1 RX, same physical assignment as JackW01) + * Pin remapping is applied in b_setup.hpp via: + * Serial2.setTX(RP2040_UART1_TX_PIN); + * Serial2.setRX(RP2040_UART1_RX_PIN); + * + * The SKR Pico has on-board TMC2209 ICs with proper PDN_UART wiring + * (both TX and RX reach each driver). No jumper is required. + * + * Endstop inputs (also usable as homing sensors): + * X-STOP -> GPIO4 (RA Hall sensor / diag input) + * Y-STOP -> GPIO3 + * Z-STOP -> GPIO25 + * E-STOP -> GPIO16 + * + * Additional I/O: + * BLTouch sensor -> GPIO22 + * BLTouch control -> GPIO29 + * NeoPixel data -> GPIO24 + */ + +#pragma once + +// ── RA axis (X slot, TMC2209 address 0) ────────────────────────────────────── +#ifndef RA_STEP_PIN + #define RA_STEP_PIN 11 +#endif +#ifndef RA_DIR_PIN + #define RA_DIR_PIN 10 +#endif +#ifndef RA_EN_PIN + #define RA_EN_PIN 12 // Individual EN pin (active LOW) +#endif +#ifndef RA_DIAG_PIN + #define RA_DIAG_PIN 4 // X-STOP input - used for Hall sensor RA homing +#endif + +// RA TMC2209 UART +#ifndef RA_SERIAL_PORT + #define RA_SERIAL_PORT Serial2 // UART1 via Philhower Serial2 +#endif +#ifndef RA_DRIVER_ADDRESS + #define RA_DRIVER_ADDRESS 0b00 // MS1=LOW, MS2=LOW -> address 0 +#endif + +// ── DEC axis (Y slot, TMC2209 address 2) ───────────────────────────────────── +#ifndef DEC_STEP_PIN + #define DEC_STEP_PIN 6 +#endif +#ifndef DEC_DIR_PIN + #define DEC_DIR_PIN 5 +#endif +#ifndef DEC_EN_PIN + #define DEC_EN_PIN 7 // Individual EN pin (active LOW) +#endif +#ifndef DEC_DIAG_PIN + #define DEC_DIAG_PIN 3 // Y-STOP input +#endif + +// DEC TMC2209 UART +#ifndef DEC_SERIAL_PORT + #define DEC_SERIAL_PORT Serial2 // Shared UART1 bus +#endif +#ifndef DEC_DRIVER_ADDRESS + #define DEC_DRIVER_ADDRESS 0b10 // MS1=LOW, MS2=HIGH -> address 2 +#endif + +// ── AZ axis (Z slot, TMC2209 address 1) ────────────────────────────────────── +#ifndef AZ_STEP_PIN + #define AZ_STEP_PIN 19 +#endif +#ifndef AZ_DIR_PIN + #define AZ_DIR_PIN 28 +#endif +#ifndef AZ_EN_PIN + #define AZ_EN_PIN 2 // Individual EN pin (active LOW) +#endif + +// AZ TMC2209 UART +#ifndef AZ_SERIAL_PORT + #define AZ_SERIAL_PORT Serial2 // Shared UART1 bus +#endif +#ifndef AZ_DRIVER_ADDRESS + #define AZ_DRIVER_ADDRESS 0b01 // MS1=HIGH, MS2=LOW -> address 1 +#endif + +// ── ALT axis (E0 slot, TMC2209 address 3) ──────────────────────────────────── +#ifndef ALT_STEP_PIN + #define ALT_STEP_PIN 14 +#endif +#ifndef ALT_DIR_PIN + #define ALT_DIR_PIN 13 +#endif +#ifndef ALT_EN_PIN + #define ALT_EN_PIN 15 // Individual EN pin (active LOW) +#endif + +// ALT TMC2209 UART +#ifndef ALT_SERIAL_PORT + #define ALT_SERIAL_PORT Serial2 // Shared UART1 bus +#endif +#ifndef ALT_DRIVER_ADDRESS + #define ALT_DRIVER_ADDRESS 0b11 // MS1=HIGH, MS2=HIGH -> address 3 +#endif + +// ── UART1 physical pin assignments ─────────────────────────────────────────── +// The SKR Pico routes UART1 to all four on-board TMC2209 ICs via a shared +// two-wire bus. GPIO8 and GPIO9 are the native UART1 TX/RX mux functions. +// b_setup.hpp calls Serial2.setTX()/setRX() before Serial2.begin(). +#ifndef RP2040_UART1_TX_PIN + #define RP2040_UART1_TX_PIN 8 +#endif +#ifndef RP2040_UART1_RX_PIN + #define RP2040_UART1_RX_PIN 9 +#endif + +// All drivers use hardware UART (Serial2). +#define SW_SERIAL_UART 0 + +// ── Debug serial port ───────────────────────────────────────────────────────── +#ifndef DEBUG_SERIAL_PORT + #define DEBUG_SERIAL_PORT Serial // USB CDC serial via Philhower core +#endif + +// ── GPS (UART0 on left-side header) ────────────────────────────────────────── +// Left-side 5-pin header: IO0=GPIO0, IO1=GPIO1, GND, 5V. +// RP2040 pin mux is fixed: GPIO0 = UART0 TX only, GPIO1 = UART0 RX only. +// GPS RX → GPIO0 / IO0 (RP2040 UART0 TX) +// GPS TX → GPIO1 / IO1 (RP2040 UART0 RX) +#define GPS_SERIAL_PORT Serial1 +#define RP2040_GPS_TX_PIN 0 // GPIO0 — UART0 TX → GPS RX +#define RP2040_GPS_RX_PIN 1 // GPIO1 — UART0 RX ← GPS TX + +// ── FAN outputs ─────────────────────────────────────────────────────────────── +// FAN1 connector: switched 12/24V via N-channel MOSFET gated by GPIO17. +// Power is set via analogWrite (0-100 %). Override RP2040_FAN1_POWER_PERCENT +// in your local config file to reduce fan speed. +#define RP2040_FAN1_PIN 17 +#ifndef RP2040_FAN1_POWER_PERCENT + #define RP2040_FAN1_POWER_PERCENT 100 +#endif From 7356649cb2a57e4994a8daa0f8056fad131e86aa Mon Sep 17 00:00:00 2001 From: Lutz Date: Sat, 10 Oct 2026 16:45:43 -0700 Subject: [PATCH 05/26] ci(rp2040): add boards to build matrix Adds rp2040_jackw01 (24 solutions) and rp2040_skr_pico (96 solutions) to the CI build matrix with conservative BOARD_SUPPORT restrictions (no LCD menu display, no gyro, no focuser; TMC2209 UART-only AZ/ALT). The SSD1306 info display matrix is extended to rp2040_skr_pico. Co-Authored-By: Claude Code --- .github/workflows/ci.yml | 2 ++ matrix_build.py | 53 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ecb3b9fa..0e6b50c8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,6 +46,8 @@ jobs: - mksgenlv1 - esp32 - ramps + - rp2040_jackw01 + - rp2040_skr_pico steps: - uses: actions/checkout@v6 - uses: ./.github/actions/setup-pio diff --git a/matrix_build.py b/matrix_build.py index 8bc80b12..ff845909 100644 --- a/matrix_build.py +++ b/matrix_build.py @@ -25,9 +25,13 @@ AVR_BOARDS = MKS_GENL_BOARDS + [ "ramps", ] +RP2040_BOARDS = [ + "rp2040_jackw01", + "rp2040_skr_pico", +] BOARDS = AVR_BOARDS + [ "esp32", -] +] + RP2040_BOARDS STEPPER_TYPES = [ "STEPPER_TYPE_NONE", @@ -176,6 +180,49 @@ def update_dict(orig, patch): "DISPLAY_TYPE_LCD_KEYPAD" ], }), + "rp2040_jackw01": update_dict(BUILD_FLAGS, { + "USE_GPS": [0], + "USE_GYRO_LEVEL": [0], + # No LCD menu display support on RP2040 (enforced by ConfigurationValidation) + "DISPLAY_TYPE": [ + "DISPLAY_TYPE_NONE" + ], + "AZ_DRIVER_TYPE": [ + "DRIVER_TYPE_NONE", + "DRIVER_TYPE_TMC2209_UART" + ], + "ALT_DRIVER_TYPE": [ + "DRIVER_TYPE_NONE", + "DRIVER_TYPE_TMC2209_UART" + ], + "FOCUS_DRIVER_TYPE": [ + "DRIVER_TYPE_NONE" + ], + "FOCUS_STEPPER_TYPE": [ + "STEPPER_TYPE_NONE" + ], + }), + "rp2040_skr_pico": update_dict(BUILD_FLAGS, { + "USE_GYRO_LEVEL": [0], + # No LCD menu display support on RP2040 (enforced by ConfigurationValidation) + "DISPLAY_TYPE": [ + "DISPLAY_TYPE_NONE" + ], + "AZ_DRIVER_TYPE": [ + "DRIVER_TYPE_NONE", + "DRIVER_TYPE_TMC2209_UART" + ], + "ALT_DRIVER_TYPE": [ + "DRIVER_TYPE_NONE", + "DRIVER_TYPE_TMC2209_UART" + ], + "FOCUS_DRIVER_TYPE": [ + "DRIVER_TYPE_NONE" + ], + "FOCUS_STEPPER_TYPE": [ + "STEPPER_TYPE_NONE" + ], + }), } SHORT_STRINGS = { @@ -296,11 +343,11 @@ def set_ci_constraints(problem): problem.addConstraint(InSetConstraint({"DISPLAY_TYPE_NONE", "DISPLAY_TYPE_LCD_KEYPAD"}), ["DISPLAY_TYPE"]) # problem.addConstraint(InSetConstraint({"DRIVER_TYPE_ULN2003"}), ["ALT_DRIVER_TYPE"]) - # Restrict INFO_DISPLAY_TYPE_I2C_SSD1306_128x64 to mksgenlv21 and esp32 only + # Restrict INFO_DISPLAY_TYPE_I2C_SSD1306_128x64 to mksgenlv21, esp32 and rp2040_skr_pico only # (just to reduce compile times) def info_display_constraint(board, info_display): if info_display == "INFO_DISPLAY_TYPE_I2C_SSD1306_128x64": - return board in ["mksgenlv21", "esp32"] + return board in ["mksgenlv21", "esp32", "rp2040_skr_pico"] return True problem.addConstraint(info_display_constraint, ["BOARD", "INFO_DISPLAY_TYPE"]) From ef906c95acc0bc3052d1cf5d8f3a0c6f2e67c62c Mon Sep 17 00:00:00 2001 From: Lutz Date: Sat, 10 Oct 2026 21:11:32 -0700 Subject: [PATCH 06/26] fix(rp2040): report RP2040 in getMountHardwareInfo The platform branch of getMountHardwareInfo() only knew ESP32 and AVR, so RP2040 builds reported "Unknown" in the hardware info string. Co-Authored-By: Claude Code --- src/Mount.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Mount.cpp b/src/Mount.cpp index d191bada..11343cb0 100644 --- a/src/Mount.cpp +++ b/src/Mount.cpp @@ -1168,6 +1168,8 @@ String Mount::getMountHardwareInfo() ret = F("ESP32,"); #elif defined(__AVR_ATmega2560__) ret = F("Mega,"); +#elif defined(ARDUINO_ARCH_RP2040) + ret = F("RP2040,"); #endif ret += F("NEMA|"); From 8a010038f22c231b6dda9a1298c1bb9e55ec31f7 Mon Sep 17 00:00:00 2001 From: Lutz Date: Sat, 10 Oct 2026 22:47:10 -0700 Subject: [PATCH 07/26] fix(logging): write each log line with a single serial write logv() issued seven separate print() calls per log line. On the arduino-pico USB CDC each write re-enters the USB mutex and the TinyUSB FIFO path, which multiplies exposure to the core's write-loop edge cases. Compose the line first and send it with one write. Co-Authored-By: Claude Code --- src/Utility.cpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/Utility.cpp b/src/Utility.cpp index 7937dda4..72d9cf59 100644 --- a/src/Utility.cpp +++ b/src/Utility.cpp @@ -410,15 +410,20 @@ void logv(int levelFlags, String input, ...) #if BUFFER_LOGS == true addToLogBuffer(formatArg(input.c_str(), argp)); #else - DEBUG_SERIAL_PORT.print("["); - DEBUG_SERIAL_PORT.print(String(now)); - DEBUG_SERIAL_PORT.print("]{"); - DEBUG_SERIAL_PORT.print(String(delta)); - DEBUG_SERIAL_PORT.print("}ms:"); - DEBUG_SERIAL_PORT.print(String(freeMemory())); - DEBUG_SERIAL_PORT.print("B: "); - DEBUG_SERIAL_PORT.println(formatArg(input.c_str(), argp)); - DEBUG_SERIAL_PORT.flush(); + // Compose the whole line and write it with a single print() call. + // The arduino-pico USB CDC write path can wedge when many small + // writes per line race the TinyUSB FIFO (each write re-enters the + // USB mutex); one write per line minimizes the exposure. + String line = "["; + line += String(now); + line += "]{"; + line += String(delta); + line += "}ms:"; + line += String(freeMemory()); + line += "B: "; + line += formatArg(input.c_str(), argp); + line += "\n"; + DEBUG_SERIAL_PORT.print(line); #endif lastLog = now; va_end(argp); From 4a3b84e58fabf42470dacdc673fdc22290f92516 Mon Sep 17 00:00:00 2001 From: Lutz Date: Sat, 10 Oct 2026 22:47:22 -0700 Subject: [PATCH 08/26] fix(rp2040): harden USB CDC serial handling - Wait for the console to connect before logging in debug builds: the CDC TX FIFO holds only ~250 bytes and with no host attached the remaining boot output is dropped, so a debug build boots invisibly. Release builds are unaffected (logging compiled out, boot headless). - Make Serial.ignoreFlowControl() opt-in via RP2040_IGNORE_CDC_FLOW_CONTROL (default off): forcing TX while no host drains the port can wedge the TinyUSB write loop while it holds the USB mutex. Needed only for hosts that open the port with DTR=false (e.g. OATControl). - Drop the RP2040 serial poll from serialLoop(): serialEvent() handles CDC RX on the Philhower core (verified on hardware with a display-less build answering :GVN#). Known issue (under investigation, likely arduino-pico/TinyUSB): builds with sparse debug levels (e.g. STEPPERS|MOUNT|INFO) can wedge within milliseconds of boot; DEBUG_NONE and DEBUG_ANY builds are stable on the same hardware. Co-Authored-By: Claude Code --- src/b_setup.hpp | 21 +++++++++++---------- src/f_serial.hpp | 2 +- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/b_setup.hpp b/src/b_setup.hpp index 72d9fabc..98a290e8 100644 --- a/src/b_setup.hpp +++ b/src/b_setup.hpp @@ -126,26 +126,27 @@ void setup() #endif #else Serial.begin(SERIAL_BAUDRATE); - #if defined(ARDUINO_ARCH_RP2040) + #if defined(ARDUINO_ARCH_RP2040) && defined(RP2040_IGNORE_CDC_FLOW_CONTROL) // OATControl (and other apps using C# SerialPort) open the port with DTR=false. // The Philhower USB CDC SerialUSB::write() gates TX on tud_cdc_connected() which // requires DTR=true, so all responses are silently dropped for those hosts. // ignoreFlowControl(true) bypasses the DTR check and always sends TX data. + // DISABLED BY DEFAULT: forcing TX while no host is draining can wedge the + // TinyUSB write loop while it holds the USB mutex (board hangs, USB stays + // enumerated). Enable only with a host that keeps the port drained. Serial.ignoreFlowControl(true); #endif #if DEBUG_LEVEL > 0 && DEBUG_SEPARATE_SERIAL == 1 DEBUG_SERIAL_PORT.begin(DEBUG_SERIAL_BAUDRATE); #endif - // RP2040 USB CDC: wait up to 3 s for the host to open the port so that - // LOG() calls below are not dropped (or do not block indefinitely). - // This only matters when DEBUG_LEVEL > 0 — in release builds LOG() is - // a no-op, so the wait is compiled out. + // RP2040 USB CDC: wait for the host to open the port before logging. + // With no host attached, the CDC TX FIFO holds only ~250 bytes and further + // writes are dropped, so a debug build boots invisibly. Waiting for the + // console keeps the whole boot visible. Release builds (DEBUG_LEVEL == 0) + // skip this entirely and boot headless. #if defined(ARDUINO_ARCH_RP2040) && DEBUG_LEVEL > 0 - { - uint32_t _cdcWaitStart = millis(); - while (!Serial && (millis() - _cdcWaitStart) < 3000UL) - { /* spin */ - } + while (!Serial) + { /* spin until the console connects */ } #endif #endif diff --git a/src/f_serial.hpp b/src/f_serial.hpp index 7fe9d624..64d5644b 100644 --- a/src/f_serial.hpp +++ b/src/f_serial.hpp @@ -19,7 +19,7 @@ void serialLoop() mount.loop(); mount.displayStepperPositionThrottled(); - #if defined(ESP32) || defined(ARDUINO_ARCH_RP2040) + #if defined(ESP32) processSerialData(); #endif From 5d3e0d2cf9bf5d6a244b70c962fbbe6afde03478 Mon Sep 17 00:00:00 2001 From: Lutz Date: Sat, 10 Oct 2026 23:03:39 -0700 Subject: [PATCH 09/26] feat(rp2040): raise stepper servicing rate to 5 kHz Add a STEPPER_CONTROL_INTERVAL_MS configuration knob (overridable in local config) with a 5 kHz default on RP2040; AVR stays at 2 kHz where higher rates interfere with serial communications. Also fix the RP2040 repeating-timer interval semantics: a positive delay_us measures from callback END to next start, silently adding the callback runtime to every period. Use a negative delay for a fixed start-to-start rate, matching the AVR TimerInterrupt behavior the stepper controller was designed for. Co-Authored-By: Claude Code --- Configuration_adv.hpp | 13 +++++++++++++ src/InterruptCallback.cpp | 11 +++++------ src/b_setup.hpp | 5 +++-- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/Configuration_adv.hpp b/Configuration_adv.hpp index c90e35b6..07b480b0 100644 --- a/Configuration_adv.hpp +++ b/Configuration_adv.hpp @@ -35,6 +35,19 @@ // //////// // MOTOR & DRIVER SETTINGS //////// // //////// +////////////////////////////////////// +// +// Interval at which the stepper control timer/interrupt services the steppers. +// Shorter intervals mean finer step timing. AVR is capped at 2 kHz: higher rates +// there interfere with serial communications. The RP2040 has ample headroom. +#ifndef STEPPER_CONTROL_INTERVAL_MS + #if defined(ARDUINO_ARCH_RP2040) + #define STEPPER_CONTROL_INTERVAL_MS 0.2f // 5 kHz + #else + #define STEPPER_CONTROL_INTERVAL_MS 0.5f // 2 kHz + #endif +#endif + ////////////////////////////////////// // // This is how many steps your stepper needs for a full rotation. diff --git a/src/InterruptCallback.cpp b/src/InterruptCallback.cpp index 18ab6601..67e7b4bd 100644 --- a/src/InterruptCallback.cpp +++ b/src/InterruptCallback.cpp @@ -75,10 +75,10 @@ bool InterruptCallback::setInterval(float intervalMs, interrupt_callback_p callb _rp2040_callback = callback; _rp2040_payload = payload; - // Positive delay_us means the period is measured from callback-start to - // callback-start (fixed wall-clock rate), which is what the stepper - // controller needs for consistent timing. - int32_t intervalUs = static_cast(intervalMs * 1000.0f); + // Negative delay_us gives a fixed wall-clock period from callback start to + // callback start (matching the AVR TimerInterrupt semantics). A positive + // delay would add the callback's own runtime to every period. + int64_t intervalUs = -static_cast(intervalMs * 1000.0f); return add_repeating_timer_us(intervalUs, rp2040_timer_isr, nullptr, &_rp2040_timer); } @@ -90,8 +90,7 @@ void InterruptCallback::stop() void InterruptCallback::start() { // Re-arm with the same interval. The stored callback/payload are still set. - int32_t intervalUs = static_cast(_rp2040_timer.delay_us); - add_repeating_timer_us(intervalUs, rp2040_timer_isr, nullptr, &_rp2040_timer); + add_repeating_timer_us(_rp2040_timer.delay_us, rp2040_timer_isr, nullptr, &_rp2040_timer); } #endif diff --git a/src/b_setup.hpp b/src/b_setup.hpp index 98a290e8..f9fbbaf6 100644 --- a/src/b_setup.hpp +++ b/src/b_setup.hpp @@ -651,8 +651,9 @@ void setup() #else #ifndef NEW_STEPPER_LIB - // 2 kHz updates (higher frequency interferes with serial communications and complete messes up OATControl communications) - if (!InterruptCallback::setInterval(0.5f, stepperControlTimerCallback, &mount)) + // Stepper servicing rate: 2 kHz on AVR (higher rates there interfere with serial + // communications and mess up OATControl), 5 kHz on RP2040 (see STEPPER_CONTROL_INTERVAL_MS). + if (!InterruptCallback::setInterval(STEPPER_CONTROL_INTERVAL_MS, stepperControlTimerCallback, &mount)) { LOG(DEBUG_MOUNT, "[SYSTEM]: CANNOT setup interrupt timer!"); } From 32cde8d19361cd0a5faa62db065432bf6e4f0b33 Mon Sep 17 00:00:00 2001 From: Lutz Date: Sat, 10 Oct 2026 23:11:55 -0700 Subject: [PATCH 10/26] fix(rp2040): bound the CDC console wait so headless boots proceed A mount powered from an external supply boots with no USB host attached, and Serial (tud_cdc_connected) never becomes true until a host asserts DTR. The previous infinite while (!Serial) spin left the firmware parked before any initialization indefinitely - no drivers, no timer, no commands - whenever it was powered without an already-open console. Wait at most 3 seconds for a console, then boot headless. Debug builds that boot headless lose the boot log (CDC drops writes with no host), but reset-with-console-open still shows the full boot. Co-Authored-By: Claude Code --- src/b_setup.hpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/b_setup.hpp b/src/b_setup.hpp index f9fbbaf6..df2fb663 100644 --- a/src/b_setup.hpp +++ b/src/b_setup.hpp @@ -139,14 +139,17 @@ void setup() #if DEBUG_LEVEL > 0 && DEBUG_SEPARATE_SERIAL == 1 DEBUG_SERIAL_PORT.begin(DEBUG_SERIAL_BAUDRATE); #endif - // RP2040 USB CDC: wait for the host to open the port before logging. - // With no host attached, the CDC TX FIFO holds only ~250 bytes and further - // writes are dropped, so a debug build boots invisibly. Waiting for the - // console keeps the whole boot visible. Release builds (DEBUG_LEVEL == 0) - // skip this entirely and boot headless. + // RP2040 USB CDC: give a console up to 3 seconds to attach so the boot + // log stays visible. Bounded, never infinite: a mount powered externally + // in the field must boot with no USB host attached. With no host attached + // the CDC TX FIFO holds only ~250 bytes and further writes are dropped, so + // a headless debug build simply boots invisibly (reset with the console + // open to see the full log). Release builds (DEBUG_LEVEL == 0) skip this + // entirely. #if defined(ARDUINO_ARCH_RP2040) && DEBUG_LEVEL > 0 - while (!Serial) - { /* spin until the console connects */ + uint32_t consoleWaitStart = millis(); + while (!Serial && (millis() - consoleWaitStart < 3000UL)) + { /* spin until the console connects or the timeout expires */ } #endif #endif From 3c3405f0a2efbcccc1bbeef924865b946ad30ec5 Mon Sep 17 00:00:00 2001 From: Lutz Date: Sat, 10 Oct 2026 23:22:51 -0700 Subject: [PATCH 11/26] fix(mount): stop overriding TMC2209 hold current to full scale The OAE firmware merge in V1.13.18 (#274) added ihold(31) after rms_current(mA, 1.0f) in the hardware-UART RA and DEC driver setup. IHOLD=31 is the top of the 5-bit current scale (~980 mA RMS per coil with 0.11R sense and vsense active), so at standstill the driver holds the motor at nearly three times the configured operating current instead of matching it - hot motors and a supply draw about 4x the expected value. The rms_current(..., 1.0f) call on the line above already sets IHOLD = IRUN, which is the documented intent ("hold current = run current"); the override only clobbers it. Note the readback log "Actual rms_current" cannot catch this: it reads cs2rms(IRUN) and never reflects IHOLD. The software-serial driver variants never got the override, so this also restores consistency between the two setup paths. Affects all TMC2209_UART boards using hardware serial since V1.13.18. Co-Authored-By: Claude Code --- src/Mount.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Mount.cpp b/src/Mount.cpp index 11343cb0..46edac3b 100644 --- a/src/Mount.cpp +++ b/src/Mount.cpp @@ -497,7 +497,6 @@ void Mount::configureRAdriver(Stream *serial, float rsense, byte driveraddress, LOG(DEBUG_STEPPERS, "[MOUNT]: Requested RA motor rms_current: %d mA", rmscurrent); _driverRA->rms_current(rmscurrent, 1.0f); //holdMultiplier = 1 to set ihold = irun _driverRA->pdn_disable(1); - _driverRA->ihold(31); #if defined(ARDUINO_ARCH_RP2040) _driverRA->toff(4); // toff>=3 required for StealthChop slow-decay phase #else @@ -590,7 +589,6 @@ void Mount::configureDECdriver(Stream *serial, float rsense, byte driveraddress, LOG(DEBUG_STEPPERS, "[MOUNT]: Requested DEC motor rms_current: %d mA", rmscurrent); _driverDEC->rms_current(rmscurrent, 1.0f); //holdMultiplier = 1 to set ihold = irun _driverDEC->pdn_disable(1); - _driverDEC->ihold(31); _driverDEC->iholddelay(15); _driverDEC->TPOWERDOWN(255); #if defined(ARDUINO_ARCH_RP2040) From bdc2b8e306e8df08e106729a61b5d3aac4f2c7b0 Mon Sep 17 00:00:00 2001 From: Lutz Date: Sun, 11 Oct 2026 13:19:01 -0700 Subject: [PATCH 12/26] fix(rp2040): always bypass CDC flow control so DTR-less hosts get replies Make Serial.ignoreFlowControl(true) unconditional on RP2040 instead of opt-in via RP2040_IGNORE_CDC_FLOW_CONTROL. Hosts that open the port without asserting DTR (OATControl and other C# SerialPort apps) were getting all firmware output - including Meade replies - silently dropped, since tud_cdc_connected() is the DTR bit. The opt-in hedge guarded against a write-path stall this core version cannot produce: SerialUSB::write() breaks immediately once the CDC TX FIFO is full and no DTR host is connected, and drops after 1 second without progress otherwise (framework-arduinopico SerialUSB.cpp). So unconditional bypass is safe for headless boots while making the mount usable from every host application without changes. As a bonus the first ~257 bytes of the boot log survive a headless boot and reach the first host that connects. Co-Authored-By: Claude Code --- src/b_setup.hpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/b_setup.hpp b/src/b_setup.hpp index df2fb663..192e04f8 100644 --- a/src/b_setup.hpp +++ b/src/b_setup.hpp @@ -126,14 +126,15 @@ void setup() #endif #else Serial.begin(SERIAL_BAUDRATE); - #if defined(ARDUINO_ARCH_RP2040) && defined(RP2040_IGNORE_CDC_FLOW_CONTROL) + #if defined(ARDUINO_ARCH_RP2040) // OATControl (and other apps using C# SerialPort) open the port with DTR=false. // The Philhower USB CDC SerialUSB::write() gates TX on tud_cdc_connected() which // requires DTR=true, so all responses are silently dropped for those hosts. - // ignoreFlowControl(true) bypasses the DTR check and always sends TX data. - // DISABLED BY DEFAULT: forcing TX while no host is draining can wedge the - // TinyUSB write loop while it holds the USB mutex (board hangs, USB stays - // enumerated). Enable only with a host that keeps the port drained. + // ignoreFlowControl(true) bypasses the DTR check so replies always flow. + // Bounded by the core: with no (or a non-DTR) host, writes stop as soon as the + // ~257-byte CDC TX FIFO is full (tud_cdc_connected() false breaks the write + // loop immediately); a connected host that stops draining is dropped after + // 1 second without progress. Headless boots never stall on logging. Serial.ignoreFlowControl(true); #endif #if DEBUG_LEVEL > 0 && DEBUG_SEPARATE_SERIAL == 1 From a7e88867750a4ecb9685b339f9e6e4921e1549fc Mon Sep 17 00:00:00 2001 From: Lutz Date: Sun, 11 Oct 2026 16:03:56 -0700 Subject: [PATCH 13/26] fix(testmenu): compare action instead of assigning in PassthroughCmd branch The PassthroughCmd arm of the action chain used a single = instead of ==, so reaching that arm assigned the String and evaluated it as truth: the branch always fired, and any unrecognized action silently entered passthrough-command mode instead of being ignored. On the RP2040 toolchain this also fails to compile (-Werror=parentheses via the Philhower core String header), which is how the CI matrix caught it. Co-Authored-By: Claude Code --- src/testmenu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/testmenu.cpp b/src/testmenu.cpp index 2649ea7d..f13e7571 100644 --- a/src/testmenu.cpp +++ b/src/testmenu.cpp @@ -479,7 +479,7 @@ void TestMenu::onKeyPressed(int key) Serial.println(F("Mount reset, EEPROM erased.")); _currentMenu->display(); } - else if (action = F("PassthroughCmd")) + else if (action == F("PassthroughCmd")) { Serial.print(F("Enter LX200-OAT command to send to mount: ")); TestMenu::setMenuState(testMenuState_t::WAITING_ON_COMMAND); From afc5d3e8d6458c441bd93112b1da5b46f5f14cb2 Mon Sep 17 00:00:00 2001 From: Lutz Date: Sun, 11 Oct 2026 16:03:57 -0700 Subject: [PATCH 14/26] ci(rp2040): restrict RA/DEC matrix driver types to TMC2209 UART The generated matrix solutions previously included A4988 and standalone driver types for the RA/DEC axes of both RP2040 boards. Those driver types need MS pins, which the boards do not route (on-board TMC2209s wired for UART only), so the affected solutions failed to build in CI with "Missing pin assignments for MS pins". Restrict RA_DRIVER_TYPE and DEC_DRIVER_TYPE to DRIVER_TYPE_TMC2209_UART for both boards, matching the AZ/ALT restrictions that were already in place. Co-Authored-By: Claude Code --- matrix_build.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/matrix_build.py b/matrix_build.py index ff845909..f629c377 100644 --- a/matrix_build.py +++ b/matrix_build.py @@ -187,6 +187,14 @@ def update_dict(orig, patch): "DISPLAY_TYPE": [ "DISPLAY_TYPE_NONE" ], + # Both RP2040 boards carry on-board TMC2209s wired for UART only; + # A4988/standalone driver types need MS pins they do not route. + "RA_DRIVER_TYPE": [ + "DRIVER_TYPE_TMC2209_UART" + ], + "DEC_DRIVER_TYPE": [ + "DRIVER_TYPE_TMC2209_UART" + ], "AZ_DRIVER_TYPE": [ "DRIVER_TYPE_NONE", "DRIVER_TYPE_TMC2209_UART" @@ -208,6 +216,14 @@ def update_dict(orig, patch): "DISPLAY_TYPE": [ "DISPLAY_TYPE_NONE" ], + # Both RP2040 boards carry on-board TMC2209s wired for UART only; + # A4988/standalone driver types need MS pins they do not route. + "RA_DRIVER_TYPE": [ + "DRIVER_TYPE_TMC2209_UART" + ], + "DEC_DRIVER_TYPE": [ + "DRIVER_TYPE_TMC2209_UART" + ], "AZ_DRIVER_TYPE": [ "DRIVER_TYPE_NONE", "DRIVER_TYPE_TMC2209_UART" From 6e32af44764f7f631c913f3cce2bd257690c6eb1 Mon Sep 17 00:00:00 2001 From: Lutz Date: Sun, 11 Oct 2026 18:02:32 -0700 Subject: [PATCH 15/26] docs(rp2040): add wiring guide for supported peripherals Documents the default pin assignments for the SKR Pico and JackW01 boards: power (including the USB-jumper/VIN contention gotcha), steppers and TMC2209 UART addresses, USB serial behavior, SSD1306 info display (with the SDA=5/SCL=4 default colliding on the SKR Pico), GPS on the SKR Pico left header, Hall homing and DEC endstop inputs, the FAN1 output, and the features that are not available on RP2040. Co-Authored-By: Claude Code --- docs/RP2040-WIRING.md | 167 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 docs/RP2040-WIRING.md diff --git a/docs/RP2040-WIRING.md b/docs/RP2040-WIRING.md new file mode 100644 index 00000000..88cfb4e5 --- /dev/null +++ b/docs/RP2040-WIRING.md @@ -0,0 +1,167 @@ +# RP2040 Wiring Guide + +Pin assignments for the two RP2040 boards supported by the OpenAstroTracker +firmware: + +| Board | Board ID | Pins file | +|---|---|---| +| BigTreeTech **SKR Pico v1.0** | `BOARD_RP2040_SKR_PICO` (2201) | `boards/RP2040_SKR_PICO/pins_RP2040_SKR_PICO.hpp` | +| **JackW01** (pi-pico-printer-board carrier) | `BOARD_RP2040_JACKW01` (2101) | `boards/RP2040_JACKW01/pins_RP2040_JACKW01.hpp` | + +Everything below reflects the **default** pin mapping compiled into the +firmware. Peripherals are enabled in your `Configuration_local_*.hpp` (see +`Configuration_local_examples/Configuration_local_rp2040_skr_pico.hpp` for a +complete annotated example). GPIO numbers refer to the `GPxx` labels on the +board, not to physical pin positions. + +All GPIO signals are **3.3 V logic**. + +--- + +## Power (SKR Pico) + +The board can be powered from USB, from the VIN terminals (12-24 V), or both - +but **never leave the USB-power jumper on while VIN is applied**. The jumper +ties the 5 V rail to USB VBUS; with a supply also feeding the rail, the +contention can hang the board during stepper driver initialization. Use: + +- **Jumper removed + VIN (12-24 V)** - normal operation. Motors and drivers are + powered, and the USB connector still works for flashing and serial (its data + lines are independent of VBUS). +- **USB only (jumper fitted)** - the firmware boots and serial works, but the + stepper drivers have no motor power; nothing moves. + +## Stepper motors + +Drivers must be `DRIVER_TYPE_TMC2209_UART` (the boards carry no A4988/standalone +wiring - MS pins are not routed). + +### SKR Pico (on-board TMC2209s) + +| Axis | Slot | STEP | DIR | EN | DIAG / endstop input | TMC2209 UART address | +|---|---|---|---|---|---|---| +| RA | X | GP11 | GP10 | GP12 | GP4 | 0 | +| DEC | Y | GP6 | GP5 | GP7 | GP3 | 2 | +| AZ | Z | GP19 | GP28 | GP2 | - | 1 | +| ALT | E0 | GP14 | GP13 | GP15 | - | 3 | + +Note the address order X=0, **Y=2, Z=1**, E0=3 - set by the MS1/MS2 strapping +on the SKR Pico PCB and the opposite of the JackW01 board. + +AZ and ALT are optional: set `AZ_DRIVER_TYPE`/`ALT_DRIVER_TYPE` to +`DRIVER_TYPE_NONE` if your mount has no vertical axis motors. + +### JackW01 (TMC2209 modules) + +| Axis | Slot | STEP | DIR | EN | DIAG / endstop input | TMC2209 UART address | +|---|---|---|---|---|---|---| +| RA | X | GP7 | GP6 | GP5 | GP4 | 0 | +| DEC | Y | GP11 | GP10 | GP5 | GP3 | 1 | +| AZ | Z | GP13 | GP12 | GP5 | - | 2 | +| ALT | E | GP15 | GP14 | GP5 | - | 3 | + +- **EN is shared**: all four enable lines are tied to GP5, so enable/disable + always affects every axis. Per-axis current control happens over UART + (IRUN/IHOLD) instead. +- Use BTT TMC2209 modules with the PDN_UART pad bridge (the on-board resistor + linking RESET/TX and MS3/RX pads to PDN_UART). The carrier routes UART1 + (GP8 TX, GP9 RX) to the driver sockets through R202/R201. + +## USB serial (control and flashing) + +- The USB port enumerates as a virtual COM port (USB CDC) and carries the + Meade/LX200 protocol used by OATControl, the ASCOM driver, and INDI. No + handshaking lines are required - hosts that open the port without asserting + DTR still receive replies. +- Flashing: the board resets into BOOTSEL mode when a serial port opens at + 1200 baud (the standard arduino-pico upload path), or hold BOOTSEL while + applying power. +- `:XGM#` reports `RP2040` as the hardware type. + +## Info display (SSD1306 128x64 OLED, I2C) + +Config keys (set in your local config): + +```cpp +#define INFO_DISPLAY_TYPE INFO_DISPLAY_TYPE_I2C_SSD1306_128x64 +#define INFO_DISPLAY_I2C_ADDRESS 0x3C +#define INFO_DISPLAY_I2C_SDA_PIN 20 +#define INFO_DISPLAY_I2C_SCL_PIN 21 +#define INFO_DISPLAY_UPSIDE_DOWN 0 // 1 = rotate 180 degrees +#define INFO_DISPLAY_MIRRORED 0 // 1 = flip horizontally +``` + +> **Important:** the global firmware defaults are SDA=5 / SCL=4. Those pins +> collide on the SKR Pico (GP5 is DEC direction, GP4 is the RA homing input), +> so always set the pins explicitly - GP20/GP21 are the recommended free pair. + +- **SKR Pico**: SDA = GP20, SCL = GP21 (I2C0). Power the display from 3.3 V. +- **JackW01**: the pins file does not reserve display pins; pick any two free + I2C-capable GPIOs (GP20/GP21 work here too) and set the same keys. + +## GPS (SKR Pico) + +Wired to the left-side 5-pin header (IO0, IO1, GND, 5V) using UART0: + +| GPS module pin | Connect to | RP2040 GPIO | +|---|---|---| +| RX (module input) | IO0 | GP0 (MCU TX - fixed mux, TX only) | +| TX (module output) | IO1 | GP1 (MCU RX - fixed mux, RX only) | +| VCC | 5V | - | +| GND | GND | - | + +Enable with `#define USE_GPS 1`. Tested with an ATGM336H-5N; any GPS module +with a 3.3 V UART output works (the RP2040 GPIO are not 5 V tolerant). + +The JackW01 board has no default GPS wiring; leave `USE_GPS` at 0. + +## Hall homing sensors (RA and DEC) + +Active-LOW inputs on the endstop headers: + +| Axis | Input | GPIO | Config | +|---|---|---|---| +| RA | X-STOP | GP4 | `USE_HALL_SENSOR_RA_AUTOHOME`, `RA_HOMING_SENSOR_PIN`, `RA_HOMING_SENSOR_ACTIVE_STATE LOW` | +| DEC | Y-STOP | GP3 | `USE_HALL_SENSOR_DEC_AUTOHOME`, `DEC_HOMING_SENSOR_PIN`, `DEC_HOMING_SENSOR_ACTIVE_STATE LOW` | + +The inputs are configured without pull-ups; open-drain Hall sensors need an +external pull-up (10 kOhm to 3.3 V). The search distance defaults to 30 degrees +(`RA_HOMING_SENSOR_SEARCH_DEGREES` etc. in `Configuration_adv.hpp`). + +## DEC endstops (SKR Pico) + +The two remaining endstop inputs can back up Hall homing with hardware limits: + +| Limit | Input | GPIO | Config key | +|---|---|---|---| +| DEC down | Z-STOP | GP25 | `DEC_ENDSWITCH_DOWN_SENSOR_PIN` | +| DEC up | E-STOP | GP16 | `DEC_ENDSWITCH_UP_SENSOR_PIN` | + +Both are active LOW (`DEC_END_SWITCH_ACTIVE_STATE`). RA endstops have no +default wiring on these boards - all four endstop inputs are allocated above. + +## Fan (SKR Pico) + +The FAN1 header is switched by a MOSFET on GP17 and carries the VIN rail +(12/24 V). Set the power percentage in your config: + +```cpp +#define RP2040_FAN1_POWER_PERCENT 60 // 0-100, default 100 +``` + +## Not available by default on RP2040 + +- **LCD menu display** - `DISPLAY_TYPE` must be `DISPLAY_TYPE_NONE` + (enforced at compile time) +- **Gyro auto-leveling** - `USE_GYRO_LEVEL` must be 0 +- **Focuser stepper** - all four driver slots are used by RA/DEC/AZ/ALT +- **Dew heater output** - no pin is wired on these boards +- **WiFi/Bluetooth** - ESP32 builds only +- SKR Pico's NeoPixel (GP24) and BLTouch (GP22/GP29) pins exist on the board + but are unused by the OAT firmware + +--- + +Source of truth for any pin: the pins files linked at the top. If your wiring +needs differ, every pin macro is `#ifndef`-guarded and can be overridden in +your local configuration file. From 5c9a1abfcbbddc673dd75faff06d92f33718c142 Mon Sep 17 00:00:00 2001 From: Lutz Date: Sun, 11 Oct 2026 22:09:09 -0700 Subject: [PATCH 16/26] fix(rp2040): correct SKR Pico info display pins (GP0/GP1, not GP20/21) Bench testing on the SKR Pico v1.0 revealed that GP20/GP21 cannot be used for the I2C info display: both only drive on-board MOSFETs (HB/FAN3 and the opto-isolated Laser output) and are never exposed as raw GPIO on any connector. Wiring a display to those power pins hangs the I2C bus and with it the firmware loop (USB stays enumerated, serial goes deaf). - Default the info display to GP0/GP1 on the SKR Pico (the only header-accessible I2C0 pair, on the left-side header) and to GP20/GP21 on the JackW01; ConfigurationValidation now rejects display pins on GP20/GP21 for the SKR Pico, and the display+GPS combination (shared pair) - matrix_build: stop generating skr_pico display+GPS solutions (would now fail) - Example config, wiring doc and wiki page updated accordingly Bench-verified: SSD1306 on GP0/GP1 renders, serial stays responsive. Co-Authored-By: Claude Code --- Configuration.hpp | 18 ++++++++-- ConfigurationValidation.hpp | 11 +++++++ .../Configuration_local_rp2040_skr_pico.hpp | 10 ++++++ docs/RP2040-WIRING.md | 33 +++++++++++-------- matrix_build.py | 9 +++++ 5 files changed, 66 insertions(+), 15 deletions(-) diff --git a/Configuration.hpp b/Configuration.hpp index 353208bd..238a5f2f 100644 --- a/Configuration.hpp +++ b/Configuration.hpp @@ -64,10 +64,24 @@ #define INFO_DISPLAY_I2C_ADDRESS 0x3C #endif #ifndef INFO_DISPLAY_I2C_SDA_PIN - #define INFO_DISPLAY_I2C_SDA_PIN 5 + #if (BOARD == BOARD_RP2040_SKR_PICO) + // The SKR Pico has exactly one header-accessible I2C-capable GPIO pair: + // GP0/GP1 on the left-side header (shared with the default GPS wiring). + #define INFO_DISPLAY_I2C_SDA_PIN 0 + #elif (BOARD == BOARD_RP2040_JACKW01) + #define INFO_DISPLAY_I2C_SDA_PIN 20 + #else + #define INFO_DISPLAY_I2C_SDA_PIN 5 + #endif #endif #ifndef INFO_DISPLAY_I2C_SCL_PIN - #define INFO_DISPLAY_I2C_SCL_PIN 4 + #if (BOARD == BOARD_RP2040_SKR_PICO) + #define INFO_DISPLAY_I2C_SCL_PIN 1 + #elif (BOARD == BOARD_RP2040_JACKW01) + #define INFO_DISPLAY_I2C_SCL_PIN 21 + #else + #define INFO_DISPLAY_I2C_SCL_PIN 4 + #endif #endif #ifndef INFO_DISPLAY_UPSIDE_DOWN #define INFO_DISPLAY_UPSIDE_DOWN 0 diff --git a/ConfigurationValidation.hpp b/ConfigurationValidation.hpp index 190d306e..cee045b4 100644 --- a/ConfigurationValidation.hpp +++ b/ConfigurationValidation.hpp @@ -174,6 +174,17 @@ #error Unsupported GPS configuration. Use at own risk. #endif +// RP2040 SKR Pico: info display pin sharing. +#if defined(ARDUINO_ARCH_RP2040) && (BOARD == BOARD_RP2040_SKR_PICO) && (INFO_DISPLAY_TYPE != INFO_DISPLAY_TYPE_NONE) + #if (USE_GPS == 1) + #error On the SKR Pico the info display and GPS share GP0/GP1 on the left-side header. Enable only one, or remap the pins explicitly. + #endif + #if (INFO_DISPLAY_I2C_SDA_PIN == 20) || (INFO_DISPLAY_I2C_SCL_PIN == 21) || (INFO_DISPLAY_I2C_SDA_PIN == 21) \ + || (INFO_DISPLAY_I2C_SCL_PIN == 20) + #error GP20/GP21 on the SKR Pico only drive on-board MOSFETs (HB/FAN/Laser power outputs); they are not exposed as GPIO on any connector and cannot be used for I2C. Use GP0/GP1 on the left-side header. + #endif +#endif + #if (USE_GYRO_LEVEL == 0) // Baseline configuration without gyro is valid #elif defined(ESP32) || defined(__AVR_ATmega2560__) diff --git a/Configuration_local_examples/Configuration_local_rp2040_skr_pico.hpp b/Configuration_local_examples/Configuration_local_rp2040_skr_pico.hpp index a757cfe5..309fcae2 100644 --- a/Configuration_local_examples/Configuration_local_rp2040_skr_pico.hpp +++ b/Configuration_local_examples/Configuration_local_rp2040_skr_pico.hpp @@ -133,6 +133,16 @@ #define RA_HOMING_SENSOR_PIN 4 // GPIO4 = RA_DIAG_PIN (X-STOP) #define RA_HOMING_SENSOR_ACTIVE_STATE LOW // sensor pulls LOW when active +// ── Info display (alternative to GPS) ───────────────────────────────────────── +// The SKR Pico has exactly one header-accessible I2C-capable GPIO pair: GP0/GP1 +// on the left-side header (IO0/IO1/GND/5V). This example uses it for GPS below. +// For an SSD1306 128x64 info display instead, set USE_GPS to 0 and enable: +// #define INFO_DISPLAY_TYPE INFO_DISPLAY_TYPE_I2C_SSD1306_128x64 +// (SDA/SCL then default to GP0/GP1: SDA->IO0, SCL->IO1, VCC->5V, GND->GND.) +// NOTE: GP20/GP21 must NOT be used for the display on this board - they only +// drive the HB/FAN/Laser MOSFET power outputs and never reach a connector as +// raw GPIO (wiring I2C there hangs the bus). Enforced by ConfigurationValidation. + // ── GPS ─────────────────────────────────────────────────────────────────────── // ATGM336H-5N wired to left-side header: GPS TX→IO1, GPS RX→IO0, VCC→5V, GND. // GPS_SERIAL_PORT, RP2040_GPS_TX_PIN, RP2040_GPS_RX_PIN defined in pins file. diff --git a/docs/RP2040-WIRING.md b/docs/RP2040-WIRING.md index 88cfb4e5..c03bf96d 100644 --- a/docs/RP2040-WIRING.md +++ b/docs/RP2040-WIRING.md @@ -80,24 +80,29 @@ AZ and ALT are optional: set `AZ_DRIVER_TYPE`/`ALT_DRIVER_TYPE` to ## Info display (SSD1306 128x64 OLED, I2C) -Config keys (set in your local config): +Config keys (set in your local config; the pins default correctly per board): ```cpp #define INFO_DISPLAY_TYPE INFO_DISPLAY_TYPE_I2C_SSD1306_128x64 -#define INFO_DISPLAY_I2C_ADDRESS 0x3C -#define INFO_DISPLAY_I2C_SDA_PIN 20 -#define INFO_DISPLAY_I2C_SCL_PIN 21 -#define INFO_DISPLAY_UPSIDE_DOWN 0 // 1 = rotate 180 degrees -#define INFO_DISPLAY_MIRRORED 0 // 1 = flip horizontally +#define INFO_DISPLAY_I2C_ADDRESS 0x3C // default +#define INFO_DISPLAY_UPSIDE_DOWN 0 // 1 = rotate 180 degrees +#define INFO_DISPLAY_MIRRORED 0 // 1 = flip horizontally ``` -> **Important:** the global firmware defaults are SDA=5 / SCL=4. Those pins -> collide on the SKR Pico (GP5 is DEC direction, GP4 is the RA homing input), -> so always set the pins explicitly - GP20/GP21 are the recommended free pair. - -- **SKR Pico**: SDA = GP20, SCL = GP21 (I2C0). Power the display from 3.3 V. -- **JackW01**: the pins file does not reserve display pins; pick any two free - I2C-capable GPIOs (GP20/GP21 work here too) and set the same keys. +- **SKR Pico**: SDA = GP0, SCL = GP1 (I2C0) — the only header-accessible + I2C-capable GPIO pair on this board, and the firmware default when the + display is enabled. Wire SDA→IO0, SCL→IO1, VCC→5V, GND→GND, all on the + left-side header (bench-verified with a common 4-pin SSD1306 module on 5V). + **GP0/GP1 are shared with the default GPS wiring** — enable either the + display or GPS, not both (enforced at compile time). +- **JackW01**: defaults are SDA = GP20, SCL = GP21 (free on that carrier); + override with `INFO_DISPLAY_I2C_SDA_PIN`/`..._SCL_PIN` to use other pins. + +> **Important (SKR Pico):** do **not** use GP20/GP21 for the display on the SKR +> Pico. They only drive on-board MOSFETs (the HB/FAN/Laser power outputs, +> labelled + and − on the board) and are never exposed as raw GPIO on any +> connector. Wiring an I2C display to those pins hangs the bus and the +> firmware (enforced at compile time). ## GPS (SKR Pico) @@ -112,6 +117,8 @@ Wired to the left-side 5-pin header (IO0, IO1, GND, 5V) using UART0: Enable with `#define USE_GPS 1`. Tested with an ATGM336H-5N; any GPS module with a 3.3 V UART output works (the RP2040 GPIO are not 5 V tolerant). +GP0/GP1 are shared with the info display's default pins on this board — +enable either GPS or the display, not both (enforced at compile time). The JackW01 board has no default GPS wiring; leave `USE_GPS` at 0. diff --git a/matrix_build.py b/matrix_build.py index f629c377..56148c09 100644 --- a/matrix_build.py +++ b/matrix_build.py @@ -367,6 +367,15 @@ def info_display_constraint(board, info_display): return True problem.addConstraint(info_display_constraint, ["BOARD", "INFO_DISPLAY_TYPE"]) + # SKR Pico: the info display (defaults to GP0/GP1) and GPS share the only + # free header I2C/UART pair; ConfigurationValidation rejects the combo. + def skr_pico_gps_display_constraint(board, gps, info_display): + if board == "rp2040_skr_pico" and gps == 1 and info_display == "INFO_DISPLAY_TYPE_I2C_SSD1306_128x64": + return False + return True + + problem.addConstraint(skr_pico_gps_display_constraint, ["BOARD", "USE_GPS", "INFO_DISPLAY_TYPE"]) + def print_solutions_matrix(solutions, short_strings=False): def get_value(vb, vk): From da87b68c42b7e6b97daedea21539322a5821e203 Mon Sep 17 00:00:00 2001 From: Lutz Date: Sun, 11 Oct 2026 22:20:09 -0700 Subject: [PATCH 17/26] docs(rp2040): drop DIAG pin references; state StallGuard autohome unsupported The TMC2209 DIAG outputs are irrelevant for the OAT firmware on these boards (StallGuard-based autohome is not supported - Hall sensor homing uses the endstop inputs instead), so the wiring tables now name the column plainly 'Endstop input' and the not-supported lists spell out the limitation. Example config comments no longer mention RA_DIAG_PIN. Co-Authored-By: Claude Code --- .../Configuration_local_rp2040_skr_pico.hpp | 6 +++--- docs/RP2040-WIRING.md | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Configuration_local_examples/Configuration_local_rp2040_skr_pico.hpp b/Configuration_local_examples/Configuration_local_rp2040_skr_pico.hpp index 309fcae2..2fbe97ac 100644 --- a/Configuration_local_examples/Configuration_local_rp2040_skr_pico.hpp +++ b/Configuration_local_examples/Configuration_local_rp2040_skr_pico.hpp @@ -16,7 +16,7 @@ * Stepper slot : E0 -> ALT (TMC2209, UART addr 3) * Motor rating : 0.9 deg / step (400 SPR), 470 mA * Pulley : 16T aluminium GT2 - * RA homing : Hall sensor on GPIO4 (X-STOP / RA_DIAG_PIN) + * RA homing : Hall sensor on GPIO4 (X-STOP) * * All pin assignments are in boards/RP2040_SKR_PICO/pins_RP2040_SKR_PICO.hpp. * R_SENSE (0.11 ohm) is set globally in src/a_inits.hpp for all TMC2209_UART @@ -124,13 +124,13 @@ #endif // ── RA Hall sensor auto-home ────────────────────────────────────────────────── -// Hall sensor is wired to GPIO4 (X-STOP input / RA_DIAG_PIN on SKR Pico). +// Hall sensor is wired to GPIO4 (X-STOP input on SKR Pico). // Active state LOW: sensor pulls GPIO4 LOW when the magnet is present. // Search distance: 30° default (RA_HOMING_SENSOR_SEARCH_DEGREES in Configuration_adv.hpp). // GPIO4 is configured INPUT (no pull-up); add external 10kΩ to 3.3V if sensor // is open-drain, or change to INPUT_PULLUP in b_setup.hpp. #define USE_HALL_SENSOR_RA_AUTOHOME 1 -#define RA_HOMING_SENSOR_PIN 4 // GPIO4 = RA_DIAG_PIN (X-STOP) +#define RA_HOMING_SENSOR_PIN 4 // GPIO4 (X-STOP) #define RA_HOMING_SENSOR_ACTIVE_STATE LOW // sensor pulls LOW when active // ── Info display (alternative to GPS) ───────────────────────────────────────── diff --git a/docs/RP2040-WIRING.md b/docs/RP2040-WIRING.md index c03bf96d..78cddf01 100644 --- a/docs/RP2040-WIRING.md +++ b/docs/RP2040-WIRING.md @@ -38,7 +38,7 @@ wiring - MS pins are not routed). ### SKR Pico (on-board TMC2209s) -| Axis | Slot | STEP | DIR | EN | DIAG / endstop input | TMC2209 UART address | +| Axis | Slot | STEP | DIR | EN | Endstop input | TMC2209 UART address | |---|---|---|---|---|---|---| | RA | X | GP11 | GP10 | GP12 | GP4 | 0 | | DEC | Y | GP6 | GP5 | GP7 | GP3 | 2 | @@ -53,7 +53,7 @@ AZ and ALT are optional: set `AZ_DRIVER_TYPE`/`ALT_DRIVER_TYPE` to ### JackW01 (TMC2209 modules) -| Axis | Slot | STEP | DIR | EN | DIAG / endstop input | TMC2209 UART address | +| Axis | Slot | STEP | DIR | EN | Endstop input | TMC2209 UART address | |---|---|---|---|---|---|---| | RA | X | GP7 | GP6 | GP5 | GP4 | 0 | | DEC | Y | GP11 | GP10 | GP5 | GP3 | 1 | @@ -158,6 +158,8 @@ The FAN1 header is switched by a MOSFET on GP17 and carries the VIN rail ## Not available by default on RP2040 +- **StallGuard driver autohome** (`USE_AUTOHOME`) - not supported on these + boards; use Hall sensor homing instead (the DIAG outputs are unused) - **LCD menu display** - `DISPLAY_TYPE` must be `DISPLAY_TYPE_NONE` (enforced at compile time) - **Gyro auto-leveling** - `USE_GYRO_LEVEL` must be 0 From 5db9a4df5fafb4c0ba5495862d4569d09c42f9cd Mon Sep 17 00:00:00 2001 From: Lutz Date: Sun, 11 Oct 2026 22:35:15 -0700 Subject: [PATCH 18/26] fix(config): drop StallGuard DIAG pragma messages The optional AZ/ALT DIAG pin checks printed a pragma message on every RP2040 build (both boards leave AZ/ALT DIAG unwired). StallGuard-based homing is not supported by the OAT firmware on these boards - Hall sensor homing via the endstop inputs is the supported path - so the messages are pure noise. Remove the checks; the pins stay optional. Co-Authored-By: Claude Code --- ConfigurationValidation.hpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/ConfigurationValidation.hpp b/ConfigurationValidation.hpp index cee045b4..386bb1cf 100644 --- a/ConfigurationValidation.hpp +++ b/ConfigurationValidation.hpp @@ -251,12 +251,6 @@ // Required pin assignments missing (ATmega uses SoftwareSerial for this driver) #error Missing pin assignments for configured AZ DRIVER_TYPE_TMC2209_UART driver #endif - #if !defined(AZ_DIAG_PIN) - // AZ_DIAG_PIN (TMC2209 DIAG output) is used only for stallGuard-based homing. - // It is optional: omit it if your hardware does not wire the DIAG output to a GPIO. - // Without it, stallGuard homing is unavailable but all other AZ motion works normally. - #pragma message "AZ_DIAG_PIN not defined. StallGuard homing unavailable for AZ axis." - #endif #if !((defined(AZ_SERIAL_PORT_TX) && defined(AZ_SERIAL_PORT_RX)) || defined(AZ_SERIAL_PORT)) // Required pin assignments missing for UART serial #error Missing pin assignments for configured AZ DRIVER_TYPE_TMC2209_UART driver serial connection @@ -275,12 +269,6 @@ // Required pin assignments missing (ATmega uses SoftwareSerial for this driver) #error Missing pin assignments for configured ALT DRIVER_TYPE_TMC2209_UART driver #endif - #if !defined(ALT_DIAG_PIN) - // ALT_DIAG_PIN (TMC2209 DIAG output) is used only for stallGuard-based homing. - // It is optional: omit it if your hardware does not wire the DIAG output to a GPIO. - // Without it, stallGuard homing is unavailable but all other ALT motion works normally. - #pragma message "ALT_DIAG_PIN not defined. StallGuard homing unavailable for ALT axis." - #endif #if !((defined(ALT_SERIAL_PORT_TX) && defined(ALT_SERIAL_PORT_RX)) || defined(ALT_SERIAL_PORT)) // Required pin assignments missing for UART serial #error Missing pin assignments for configured ALT DRIVER_TYPE_TMC2209_UART driver serial connection From 9a48e9d54c9e4362526de903e027676ade3987c8 Mon Sep 17 00:00:00 2001 From: Lutz Date: Sun, 11 Oct 2026 22:50:33 -0700 Subject: [PATCH 19/26] Changed debug level test to inequality --- src/Mount.cpp | 11 ++++++++--- src/SSD1306_128x64_Display.cpp | 6 +++++- src/Utility.cpp | 6 +++--- src/Utility.hpp | 2 +- src/b_setup.hpp | 4 ++-- 5 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/Mount.cpp b/src/Mount.cpp index 46edac3b..6bd6a4b5 100644 --- a/src/Mount.cpp +++ b/src/Mount.cpp @@ -3399,7 +3399,12 @@ void Mount::updateInfoDisplay() // timeout, causing ASCOM errors. // We will update at 30Hz when idle, 5Hz when slewing one axis and skip updates when slewing both. + const bool isSlewingAny = (slewStatus() & (SLEWING_DEC | SLEWING_RA)) != 0; + int refreshRateHz = 30; + #if defined(ARDUINO_ARCH_RP2040) + refreshRateHz = isSlewingAny ? 15 : 30; + #else const bool isSlewingRAandDEC = (slewStatus() & (SLEWING_DEC | SLEWING_RA)) == (SLEWING_DEC | SLEWING_RA); if (isSlewingRAandDEC) { @@ -3409,7 +3414,7 @@ void Mount::updateInfoDisplay() { refreshRateHz = 5; // Update the display slower } - + #endif const long now = millis(); if (now - _lastInfoUpdate > (1000 / refreshRateHz)) { @@ -3788,7 +3793,7 @@ void Mount::moveSteppersTo(float targetRASteps, float targetDECSteps, StepperAxi { if (_decUpperLimit != 0) { -#if DEBUG_LEVEL > 0 +#if DEBUG_LEVEL != 0 if (targetDECSteps > (float) _decUpperLimit) { LOG(DEBUG_STEPPERS, "[STEPPERS]: MoveSteppersTo: DEC Upper Limit enforced. To: %l", _decUpperLimit); @@ -3799,7 +3804,7 @@ void Mount::moveSteppersTo(float targetRASteps, float targetDECSteps, StepperAxi if (_decLowerLimit != 0) { -#if DEBUG_LEVEL > 0 +#if DEBUG_LEVEL != 0 if (targetDECSteps < (float) _decLowerLimit) { LOG(DEBUG_STEPPERS, "[STEPPERS]: MoveSteppersTo: DEC Lower Limit enforced. To: %l", _decLowerLimit); diff --git a/src/SSD1306_128x64_Display.cpp b/src/SSD1306_128x64_Display.cpp index bae3c33b..665f6bde 100644 --- a/src/SSD1306_128x64_Display.cpp +++ b/src/SSD1306_128x64_Display.cpp @@ -124,7 +124,11 @@ void SDD1306OLED128x64::drawIndicators(Mount *mount) _display->drawString(11, 59, F("L")); // Memory chip icon _display->setFont(Bitmap3x5); long availMem = freeMemory(); - if (availMem > 9999) + if (availMem > 999999) + { + _display->drawString(20, 59, String(availMem / 1024 / 1024, 1) + "M"); + } + else if (availMem > 9999) { _display->drawString(20, 59, String(availMem / 1024) + "K"); } diff --git a/src/Utility.cpp b/src/Utility.cpp index 72d9cf59..69739ee7 100644 --- a/src/Utility.cpp +++ b/src/Utility.cpp @@ -3,11 +3,11 @@ #include "../Configuration.hpp" #include "Utility.hpp" -#if DEBUG_LEVEL > 0 +#if DEBUG_LEVEL != 0 #include #endif -#if DEBUG_LEVEL > 0 +#if DEBUG_LEVEL != 0 unsigned long RealTime::_pausedTime = 0; unsigned long RealTime::_suspendStart = 0; int RealTime::_suspended = 0; @@ -293,7 +293,7 @@ int freeMemory() } #endif -#if DEBUG_LEVEL > 0 +#if DEBUG_LEVEL != 0 String formatArg(const char *input, va_list args) { diff --git a/src/Utility.hpp b/src/Utility.hpp index d8801ebd..91847c6c 100644 --- a/src/Utility.hpp +++ b/src/Utility.hpp @@ -10,7 +10,7 @@ String getLogBuffer(); int freeMemory(); -#if DEBUG_LEVEL > 0 +#if DEBUG_LEVEL != 0 #define LOG(level, format, ...) logv((level), (F(format)), ##__VA_ARGS__) // Realtime timer class using microseconds to time stuff diff --git a/src/b_setup.hpp b/src/b_setup.hpp index 192e04f8..ac45478c 100644 --- a/src/b_setup.hpp +++ b/src/b_setup.hpp @@ -137,7 +137,7 @@ void setup() // 1 second without progress. Headless boots never stall on logging. Serial.ignoreFlowControl(true); #endif - #if DEBUG_LEVEL > 0 && DEBUG_SEPARATE_SERIAL == 1 + #if DEBUG_LEVEL != 0 && DEBUG_SEPARATE_SERIAL == 1 DEBUG_SERIAL_PORT.begin(DEBUG_SERIAL_BAUDRATE); #endif // RP2040 USB CDC: give a console up to 3 seconds to attach so the boot @@ -147,7 +147,7 @@ void setup() // a headless debug build simply boots invisibly (reset with the console // open to see the full log). Release builds (DEBUG_LEVEL == 0) skip this // entirely. - #if defined(ARDUINO_ARCH_RP2040) && DEBUG_LEVEL > 0 + #if defined(ARDUINO_ARCH_RP2040) && DEBUG_LEVEL != 0 uint32_t consoleWaitStart = millis(); while (!Serial && (millis() - consoleWaitStart < 3000UL)) { /* spin until the console connects or the timeout expires */ From ca166d8f30179d1480276898e4e3020846354610 Mon Sep 17 00:00:00 2001 From: openastrotech-bot Date: Mon, 12 Oct 2026 05:50:52 +0000 Subject: [PATCH 20/26] style: apply clang-format fixes --- src/Mount.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Mount.cpp b/src/Mount.cpp index 6bd6a4b5..2517a636 100644 --- a/src/Mount.cpp +++ b/src/Mount.cpp @@ -3401,10 +3401,10 @@ void Mount::updateInfoDisplay() const bool isSlewingAny = (slewStatus() & (SLEWING_DEC | SLEWING_RA)) != 0; - int refreshRateHz = 30; - #if defined(ARDUINO_ARCH_RP2040) - refreshRateHz = isSlewingAny ? 15 : 30; - #else + int refreshRateHz = 30; + #if defined(ARDUINO_ARCH_RP2040) + refreshRateHz = isSlewingAny ? 15 : 30; + #else const bool isSlewingRAandDEC = (slewStatus() & (SLEWING_DEC | SLEWING_RA)) == (SLEWING_DEC | SLEWING_RA); if (isSlewingRAandDEC) { @@ -3414,7 +3414,7 @@ void Mount::updateInfoDisplay() { refreshRateHz = 5; // Update the display slower } - #endif + #endif const long now = millis(); if (now - _lastInfoUpdate > (1000 / refreshRateHz)) { From d442e01843e1d0380e78a7bd1c571b9200b4cd3f Mon Sep 17 00:00:00 2001 From: Lutz Date: Sun, 11 Oct 2026 23:42:16 -0700 Subject: [PATCH 21/26] fix(display): draw logo header on every console frame; uppercase FW version Boot console updates (addConsoleText/updateConsoleText render with a null content callback) never drew the header, so the logo only appeared via ISR-driven renders in the ~0.5s window between stepper-timer start and console-mode end - invisible on a fast RP2040 boot and fragile everywhere. Extract drawHeader() from drawScreen() and call it from the base render() on every console-mode frame, so the logo and product name show from the first boot line through BOOT COMPLETE on all platforms. Also uppercase the FW version line: Bitmap3x5 covers only chars 32-90 and release-please now stamps VERSION with a lowercase v prefix, which rendered as an out-of-range glyph. Console lines already uppercase. Bench-verified on the SKR Pico (SSD1306 on GP0/GP1). Co-Authored-By: Claude Code --- src/InfoDisplayRender.hpp | 10 ++++++++++ src/SSD1306_128x64_Display.cpp | 35 +++++++++++++++++++++------------- src/SSD1306_128x64_Display.hpp | 3 +++ 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/src/InfoDisplayRender.hpp b/src/InfoDisplayRender.hpp index 3f9569bd..79287764 100644 --- a/src/InfoDisplayRender.hpp +++ b/src/InfoDisplayRender.hpp @@ -18,6 +18,10 @@ class InfoDisplayRender int _curLine; public: + // Draws the console-mode header (logo and product name). + // Overridden by subclasses; the default draws nothing. + virtual void drawHeader() {}; + InfoDisplayRender() { _consoleMode = true; @@ -56,6 +60,12 @@ class InfoDisplayRender { drawContentFunction(this); } + else if (_consoleMode) + { + // Console-text updates arrive without a content callback; draw the + // header here so the boot console carries the logo on every frame. + drawHeader(); + } if (_consoleMode) { diff --git a/src/SSD1306_128x64_Display.cpp b/src/SSD1306_128x64_Display.cpp index 665f6bde..945d87f7 100644 --- a/src/SSD1306_128x64_Display.cpp +++ b/src/SSD1306_128x64_Display.cpp @@ -55,25 +55,30 @@ void SDD1306OLED128x64::renderCallback(void *context) display->drawScreen(); } -void SDD1306OLED128x64::drawScreen() +// Console-mode header, in the area 0,0 to 127,20. +// Logo on the left, product name on the right. +void SDD1306OLED128x64::drawHeader() { _display->setColor(WHITE); - if (_consoleMode) - { - // Draw header only in console mode, in the area 0,0 to 127,20 - // Logo on the left. Base class renders console output text. - _display->setFont(OATLogo); - _display->drawString(0, 0, "!"); + _display->setFont(OATLogo); + _display->drawString(0, 0, "!"); - // Name on the right - _display->setFont(Bitmap5x7); + // Name on the right + _display->setFont(Bitmap5x7); #ifdef OAE - _display->drawString(32, 6, F("OpenAstroExplorer")); + _display->drawString(32, 6, F("OpenAstroExplorer")); #elif defined(OAM) - _display->drawString(32, 6, F("OpenAstroMount")); + _display->drawString(32, 6, F("OpenAstroMount")); #else - _display->drawString(32, 6, F("OpenAstroTracker")); + _display->drawString(32, 6, F("OpenAstroTracker")); #endif +} + +void SDD1306OLED128x64::drawScreen() +{ + if (_consoleMode) + { + drawHeader(); } else { @@ -163,7 +168,11 @@ void SDD1306OLED128x64::drawIndicators(Mount *mount) break; case 3: { - _display->drawString(55, 59, (String(F(" FW ")) + String(VERSION)).c_str()); + // Bitmap3x5 has no lowercase glyphs; uppercase so release-please's + // "v" version prefix renders as V instead of an out-of-range glyph. + String fw = String(F(" FW ")) + String(VERSION); + fw.toUpperCase(); + _display->drawString(55, 59, fw.c_str()); } break; case 4: diff --git a/src/SSD1306_128x64_Display.hpp b/src/SSD1306_128x64_Display.hpp index 2cdea708..2ff75b79 100644 --- a/src/SSD1306_128x64_Display.hpp +++ b/src/SSD1306_128x64_Display.hpp @@ -59,6 +59,9 @@ class SDD1306OLED128x64 : public InfoDisplayRender void static renderCallback(void *context); void drawScreen(); + // Console-mode header: logo and product name + void drawHeader(); + // Build the display from the mount void renderScreen(void *mount); From 77770fc39151d5c416c2daeab87bfa525936c8b1 Mon Sep 17 00:00:00 2001 From: Lutz Date: Sun, 11 Oct 2026 23:42:16 -0700 Subject: [PATCH 22/26] feat(rp2040): default USB serial speed to 115200 The 19200 ASCOM default exists because the 8-bit AVR platforms cannot keep up; the RP2040 USB CDC port has no such constraint. Add SERIAL_BAUDRATE_FAST and select it automatically on ARDUINO_ARCH_RP2040, and set monitor_speed accordingly for the RP2040 environments. AVR and ESP32 are unchanged. Co-Authored-By: Claude Code --- Configuration.hpp | 7 ++++++- Constants.hpp | 1 + platformio.ini | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Configuration.hpp b/Configuration.hpp index 238a5f2f..b348dd68 100644 --- a/Configuration.hpp +++ b/Configuration.hpp @@ -178,7 +178,12 @@ * See Constants.hpp for predefined SERIAL_BAUDRATE options, or customize as required. */ #ifndef SERIAL_BAUDRATE - #define SERIAL_BAUDRATE SERIAL_BAUDRATE_ASCOM + #if defined(ARDUINO_ARCH_RP2040) + // The 19200 ASCOM default exists because the 8-bit AVR platforms cannot keep up. + #define SERIAL_BAUDRATE SERIAL_BAUDRATE_FAST + #else + #define SERIAL_BAUDRATE SERIAL_BAUDRATE_ASCOM + #endif #endif /** diff --git a/Constants.hpp b/Constants.hpp index c93cfd30..f0ef8b40 100644 --- a/Constants.hpp +++ b/Constants.hpp @@ -69,6 +69,7 @@ // USB serial port speed according to external controller #define SERIAL_BAUDRATE_ASCOM 19200 +#define SERIAL_BAUDRATE_FAST 115200 // For platforms that keep up (RP2040 USB CDC) // Wifi operating modes (ESP32 only) #define WIFI_MODE_INFRASTRUCTURE 0 // Infrastructure Only - OAT connects to an existing Router diff --git a/platformio.ini b/platformio.ini index 6dce5f47..fd850316 100644 --- a/platformio.ini +++ b/platformio.ini @@ -141,6 +141,8 @@ build_flags = [common_rp2xxx] extends = common_embedded +; The 19200 default exists for the 8-bit AVR platforms; RP2040 USB CDC keeps up at 115200. +monitor_speed = 115200 ; Use the maxgerhardt platform wrapper to access the Earle Philhower arduino-pico core. ; The official platform-raspberrypi uses the Arduino-mbed core, which has poorer ; library compatibility and no flexible UART pin remapping. From 6bcc75d4bd7b6ef3dea536a707aeecd253aeae1e Mon Sep 17 00:00:00 2001 From: Lutz Date: Sun, 11 Oct 2026 23:45:53 -0700 Subject: [PATCH 23/26] Sample Pico config for OAM --- ...le_Configuration_local_rp2040_skr_pico.hpp | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 Example_Configuration_local_rp2040_skr_pico.hpp diff --git a/Example_Configuration_local_rp2040_skr_pico.hpp b/Example_Configuration_local_rp2040_skr_pico.hpp new file mode 100644 index 00000000..d3f5b3ca --- /dev/null +++ b/Example_Configuration_local_rp2040_skr_pico.hpp @@ -0,0 +1,141 @@ +/** + * @brief Bench configuration for the BTT SKR Pico v1.0 RP2040 board. + * + * Personal local config (gitignored). Based on + * Configuration_local_examples/Configuration_local_rp2040_skr_pico.hpp, + * adapted for the bench hardware: + * - Hall homing sensors on RA (X-STOP GPIO4) AND DEC (Y-STOP GPIO3) + * - DEC endstops on Z-STOP (GPIO25, down) and E-STOP (GPIO16, up) + * - SSD1306 info display on I2C0, GP0/GP1 on the left-side header + * - GPS disabled for the bench + * + * All other pin assignments are in boards/RP2040_SKR_PICO/pins_RP2040_SKR_PICO.hpp. + */ +#pragma once + +// ── Board ───────────────────────────────────────────────────────────────────── +#define BOARD BOARD_RP2040_SKR_PICO +#define OAM +#define TEST_VERIFY_MODE 0 + +// ── Hemisphere ──────────────────────────────────────────────────────────────── +#define NORTHERN_HEMISPHERE 1 + +// ── Display ──────────────────────────────────────────────────────────────────── +// No LCD menu display (RP2040 phase 1); SSD1306 128x64 info display on I2C0. +// GP0/GP1 on the left-side header (IO0/IO1/GND/5V) - the only header-accessible +// I2C0 pair on the SKR Pico. Shares pins with the default GPS wiring, so +// USE_GPS must stay 0 while the display is enabled. +// (GP20/GP21 are MOSFET-gate-only nets on this board - HB/FAN/Laser outputs, +// never exposed as raw GPIO; wiring I2C there hangs the bus and the firmware.) +#define DISPLAY_TYPE DISPLAY_TYPE_NONE +#define INFO_DISPLAY_TYPE INFO_DISPLAY_TYPE_I2C_SSD1306_128x64 +#define INFO_DISPLAY_I2C_ADDRESS 0x3C +#define INFO_DISPLAY_I2C_SDA_PIN 0 // GP0 (I2C0 SDA, left header IO0) +#define INFO_DISPLAY_I2C_SCL_PIN 1 // GP1 (I2C0 SCL, left header IO1) +#define INFO_DISPLAY_UPSIDE_DOWN 1 +#define INFO_DISPLAY_MIRRORED 0 + +// ── Stepper control interval ───────────────────────────────────────────────── +// The RP2040 can handle a 10kHz stepper timer +#define STEPPER_CONTROL_INTERVAL_MS 0.1f // 10 kHz + +// ── Stepper motor types ─────────────────────────────────────────────────────── +#define RA_STEPPER_TYPE STEPPER_TYPE_ENABLED +#define DEC_STEPPER_TYPE STEPPER_TYPE_ENABLED +#define AZ_STEPPER_TYPE STEPPER_TYPE_ENABLED +#define ALT_STEPPER_TYPE STEPPER_TYPE_ENABLED + +// ── Stepper driver types ────────────────────────────────────────────────────── +#define RA_DRIVER_TYPE DRIVER_TYPE_TMC2209_UART +#define DEC_DRIVER_TYPE DRIVER_TYPE_TMC2209_UART +#define AZ_DRIVER_TYPE DRIVER_TYPE_TMC2209_UART +#define ALT_DRIVER_TYPE DRIVER_TYPE_TMC2209_UART + +// ── RA Settings ─────────────────────────────────────────────────────────────── +#define RA_SLEW_MICROSTEPPING 16 // µsteps used while slewing RA +#define RA_TRACKING_MICROSTEPPING 256 // µsteps used for sidereal tracking +#define RA_STEPPER_SPEED 8000 // steps/s. If SPEED and ACCELERATION numbers are the same, the spool up to full speed takes one second. +#define RA_STEPPER_ACCELERATION 8000 // steps/s/s +#define RA_MOTOR_CURRENT_RATING 1000 // mA +#define RA_OPERATING_CURRENT_SETTING 75 // % +#define RA_WHEEL_CIRCUMFERENCE 1130.97f // 360mm diam +#define RA_PULLEY_TEETH 16 +#define RA_STEPPER_SPR (400 * 9) // change to (200 * 9) for 1.8° stepper +#define RA_LIMIT_LEFT 6.0f +#define RA_LIMIT_RIGHT 6.0f +#define RA_INVERT_DIR 1 + +// ── DEC settings ──────────────────────────────────────────────────────────── +#define DEC_SLEW_MICROSTEPPING 16 // µsteps used while slewing DEC +#define DEC_GUIDE_MICROSTEPPING 256 // µsteps used for guide pulses +#define DEC_STEPPER_SPEED 8000 // steps/s. If SPEED and ACCELERATION numbers are the same, the spool up to full speed takes one second. +#define DEC_STEPPER_ACCELERATION 8000 // steps/s/s +#define DEC_MOTOR_CURRENT_RATING 1000 // mA +#define DEC_OPERATING_CURRENT_SETTING 75 // % +#define DEC_WHEEL_CIRCUMFERENCE 816.814f +#define DEC_PULLEY_TEETH 16 +#define DEC_STEPPER_SPR (400 * 9) // change to (200 * 9) for 1.8° stepper +#define DEC_LIMIT_UP 130 +#define DEC_LIMIT_DOWN 130 +#define DEC_INVERT_DIR 1 + +// ── StealthChop (silent mode) ───────────────────────────────────────────────── +#define RA_UART_STEALTH_MODE 1 +#define DEC_UART_STEALTH_MODE 1 + +// ── AZIMUTH definitions ────────────────────────────────────────────────────── +#define AZ_MICROSTEPPING 16 +#define AZ_STEPPER_SPEED 2500 +#define AZ_STEPPER_ACCELERATION 1250 +#define AZ_MOTOR_CURRENT_RATING 2000 // mA +#define AZ_OPERATING_CURRENT_SETTING 80 // % +#define AZ_STEPPER_SPR 400 +#define AZ_ALWAYS_ON 1 +#define AZ_MOTOR_HOLD_SETTING 15 +#define AZ_PULLEY_TEETH 20 +#define AZ_ROD_PITCH 1.0f // mm per full rev of stepper +#define AZ_CIRCUMFERENCE (115 * 2 * 3.1515927) +#define AZIMUTH_STEPS_PER_REV (AZ_CIRCUMFERENCE / AZ_ROD_PITCH * AZ_STEPPER_SPR * AZ_MICROSTEPPING) // Steps needed to turn AZ 360deg +#define AZ_INVERT_DIR 1 + +// ── ALTITUDE definitions ───────────────────────────────────────────────────── +#define ALT_MICROSTEPPING 32 +#define ALT_STEPPER_SPEED 2500 +#define ALT_STEPPER_ACCELERATION 1250 +#define ALT_MOTOR_CURRENT_RATING 1000 // mA +#define ALT_OPERATING_CURRENT_SETTING 70 // % +#define ALT_STEPPER_SPR 400 +#define ALT_INVERT_DIR 0 +#define ALT_ALWAYS_ON 0 + +// ── Hall sensor auto-homing (RA and DEC) ────────────────────────────────────── +// RA sensor on X-STOP (GPIO4 = RA_DIAG_PIN), DEC sensor on Y-STOP (GPIO3 = DEC_DIAG_PIN). +// Active state LOW: sensor pulls the GPIO LOW when the magnet is present. +#define USE_HALL_SENSOR_RA_AUTOHOME 0 +#define RA_HOMING_SENSOR_PIN 4 // GPIO4 = X-STOP +#define RA_HOMING_SENSOR_ACTIVE_STATE LOW + +#define USE_HALL_SENSOR_DEC_AUTOHOME 0 +#define DEC_HOMING_SENSOR_PIN 3 // GPIO3 = Y-STOP +#define DEC_HOMING_SENSOR_ACTIVE_STATE LOW + +// ── DEC endstops ────────────────────────────────────────────────────────────── +// Wired to the two remaining endstop inputs on the SKR Pico. +#define USE_DEC_END_SWITCH 0 +#define DEC_ENDSWITCH_DOWN_SENSOR_PIN 25 // GPIO25 = Z-STOP +#define DEC_ENDSWITCH_UP_SENSOR_PIN 16 // GPIO16 = E-STOP +#define DEC_END_SWITCH_ACTIVE_STATE LOW + +// ── GPS ─────────────────────────────────────────────────────────────────────── +// Disabled for the bench (no module connected). NOTE: GPS shares GP0/GP1 with +// the info display on this board - only one of the two can be enabled. +#define USE_GPS 0 + +// ── FAN (disabled for now)─────────────────────────────────────────────────────────────────────── +// #define RP2040_FAN1_POWER_PERCENT 60 + +// Track immediately after boot +#define TRACK_ON_BOOT 0 + +#define DEBUG_LEVEL (DEBUG_NONE) From 749329a1c988891593d589d84c8b38ab0c2dca97 Mon Sep 17 00:00:00 2001 From: openastrotech-bot Date: Mon, 12 Oct 2026 06:46:12 +0000 Subject: [PATCH 24/26] style: apply clang-format fixes --- ...le_Configuration_local_rp2040_skr_pico.hpp | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/Example_Configuration_local_rp2040_skr_pico.hpp b/Example_Configuration_local_rp2040_skr_pico.hpp index d3f5b3ca..e830321c 100644 --- a/Example_Configuration_local_rp2040_skr_pico.hpp +++ b/Example_Configuration_local_rp2040_skr_pico.hpp @@ -28,11 +28,11 @@ // USE_GPS must stay 0 while the display is enabled. // (GP20/GP21 are MOSFET-gate-only nets on this board - HB/FAN/Laser outputs, // never exposed as raw GPIO; wiring I2C there hangs the bus and the firmware.) -#define DISPLAY_TYPE DISPLAY_TYPE_NONE -#define INFO_DISPLAY_TYPE INFO_DISPLAY_TYPE_I2C_SSD1306_128x64 +#define DISPLAY_TYPE DISPLAY_TYPE_NONE +#define INFO_DISPLAY_TYPE INFO_DISPLAY_TYPE_I2C_SSD1306_128x64 #define INFO_DISPLAY_I2C_ADDRESS 0x3C -#define INFO_DISPLAY_I2C_SDA_PIN 0 // GP0 (I2C0 SDA, left header IO0) -#define INFO_DISPLAY_I2C_SCL_PIN 1 // GP1 (I2C0 SCL, left header IO1) +#define INFO_DISPLAY_I2C_SDA_PIN 0 // GP0 (I2C0 SDA, left header IO0) +#define INFO_DISPLAY_I2C_SCL_PIN 1 // GP1 (I2C0 SCL, left header IO1) #define INFO_DISPLAY_UPSIDE_DOWN 1 #define INFO_DISPLAY_MIRRORED 0 @@ -53,43 +53,43 @@ #define ALT_DRIVER_TYPE DRIVER_TYPE_TMC2209_UART // ── RA Settings ─────────────────────────────────────────────────────────────── -#define RA_SLEW_MICROSTEPPING 16 // µsteps used while slewing RA -#define RA_TRACKING_MICROSTEPPING 256 // µsteps used for sidereal tracking -#define RA_STEPPER_SPEED 8000 // steps/s. If SPEED and ACCELERATION numbers are the same, the spool up to full speed takes one second. -#define RA_STEPPER_ACCELERATION 8000 // steps/s/s -#define RA_MOTOR_CURRENT_RATING 1000 // mA -#define RA_OPERATING_CURRENT_SETTING 75 // % -#define RA_WHEEL_CIRCUMFERENCE 1130.97f // 360mm diam -#define RA_PULLEY_TEETH 16 -#define RA_STEPPER_SPR (400 * 9) // change to (200 * 9) for 1.8° stepper -#define RA_LIMIT_LEFT 6.0f -#define RA_LIMIT_RIGHT 6.0f -#define RA_INVERT_DIR 1 +#define RA_SLEW_MICROSTEPPING 16 // µsteps used while slewing RA +#define RA_TRACKING_MICROSTEPPING 256 // µsteps used for sidereal tracking +#define RA_STEPPER_SPEED 8000 // steps/s. If SPEED and ACCELERATION numbers are the same, the spool up to full speed takes one second. +#define RA_STEPPER_ACCELERATION 8000 // steps/s/s +#define RA_MOTOR_CURRENT_RATING 1000 // mA +#define RA_OPERATING_CURRENT_SETTING 75 // % +#define RA_WHEEL_CIRCUMFERENCE 1130.97f // 360mm diam +#define RA_PULLEY_TEETH 16 +#define RA_STEPPER_SPR (400 * 9) // change to (200 * 9) for 1.8° stepper +#define RA_LIMIT_LEFT 6.0f +#define RA_LIMIT_RIGHT 6.0f +#define RA_INVERT_DIR 1 // ── DEC settings ──────────────────────────────────────────────────────────── -#define DEC_SLEW_MICROSTEPPING 16 // µsteps used while slewing DEC -#define DEC_GUIDE_MICROSTEPPING 256 // µsteps used for guide pulses -#define DEC_STEPPER_SPEED 8000 // steps/s. If SPEED and ACCELERATION numbers are the same, the spool up to full speed takes one second. -#define DEC_STEPPER_ACCELERATION 8000 // steps/s/s -#define DEC_MOTOR_CURRENT_RATING 1000 // mA -#define DEC_OPERATING_CURRENT_SETTING 75 // % -#define DEC_WHEEL_CIRCUMFERENCE 816.814f -#define DEC_PULLEY_TEETH 16 -#define DEC_STEPPER_SPR (400 * 9) // change to (200 * 9) for 1.8° stepper -#define DEC_LIMIT_UP 130 -#define DEC_LIMIT_DOWN 130 -#define DEC_INVERT_DIR 1 +#define DEC_SLEW_MICROSTEPPING 16 // µsteps used while slewing DEC +#define DEC_GUIDE_MICROSTEPPING 256 // µsteps used for guide pulses +#define DEC_STEPPER_SPEED 8000 // steps/s. If SPEED and ACCELERATION numbers are the same, the spool up to full speed takes one second. +#define DEC_STEPPER_ACCELERATION 8000 // steps/s/s +#define DEC_MOTOR_CURRENT_RATING 1000 // mA +#define DEC_OPERATING_CURRENT_SETTING 75 // % +#define DEC_WHEEL_CIRCUMFERENCE 816.814f +#define DEC_PULLEY_TEETH 16 +#define DEC_STEPPER_SPR (400 * 9) // change to (200 * 9) for 1.8° stepper +#define DEC_LIMIT_UP 130 +#define DEC_LIMIT_DOWN 130 +#define DEC_INVERT_DIR 1 // ── StealthChop (silent mode) ───────────────────────────────────────────────── -#define RA_UART_STEALTH_MODE 1 -#define DEC_UART_STEALTH_MODE 1 +#define RA_UART_STEALTH_MODE 1 +#define DEC_UART_STEALTH_MODE 1 // ── AZIMUTH definitions ────────────────────────────────────────────────────── #define AZ_MICROSTEPPING 16 #define AZ_STEPPER_SPEED 2500 #define AZ_STEPPER_ACCELERATION 1250 #define AZ_MOTOR_CURRENT_RATING 2000 // mA -#define AZ_OPERATING_CURRENT_SETTING 80 // % +#define AZ_OPERATING_CURRENT_SETTING 80 // % #define AZ_STEPPER_SPR 400 #define AZ_ALWAYS_ON 1 #define AZ_MOTOR_HOLD_SETTING 15 @@ -112,17 +112,17 @@ // ── Hall sensor auto-homing (RA and DEC) ────────────────────────────────────── // RA sensor on X-STOP (GPIO4 = RA_DIAG_PIN), DEC sensor on Y-STOP (GPIO3 = DEC_DIAG_PIN). // Active state LOW: sensor pulls the GPIO LOW when the magnet is present. -#define USE_HALL_SENSOR_RA_AUTOHOME 0 -#define RA_HOMING_SENSOR_PIN 4 // GPIO4 = X-STOP -#define RA_HOMING_SENSOR_ACTIVE_STATE LOW +#define USE_HALL_SENSOR_RA_AUTOHOME 0 +#define RA_HOMING_SENSOR_PIN 4 // GPIO4 = X-STOP +#define RA_HOMING_SENSOR_ACTIVE_STATE LOW #define USE_HALL_SENSOR_DEC_AUTOHOME 0 -#define DEC_HOMING_SENSOR_PIN 3 // GPIO3 = Y-STOP +#define DEC_HOMING_SENSOR_PIN 3 // GPIO3 = Y-STOP #define DEC_HOMING_SENSOR_ACTIVE_STATE LOW // ── DEC endstops ────────────────────────────────────────────────────────────── // Wired to the two remaining endstop inputs on the SKR Pico. -#define USE_DEC_END_SWITCH 0 +#define USE_DEC_END_SWITCH 0 #define DEC_ENDSWITCH_DOWN_SENSOR_PIN 25 // GPIO25 = Z-STOP #define DEC_ENDSWITCH_UP_SENSOR_PIN 16 // GPIO16 = E-STOP #define DEC_END_SWITCH_ACTIVE_STATE LOW From 331c20ef62de13a8d61e60a2ffe09608fc280954 Mon Sep 17 00:00:00 2001 From: Lutz Date: Wed, 14 Oct 2026 00:46:31 -0700 Subject: [PATCH 25/26] docs(rp2040): clarify FreeRTOS mention in timer comment The old comment said the alarm API works "without relying on FreeRTOS or a second core", which reads as if FreeRTOS were an option on this platform. It was meant as a contrast to the ESP32 port, which steps from a FreeRTOS task. State that explicitly and note the Philhower core has no RTOS. Co-Authored-By: Claude Code --- src/InterruptCallback.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/InterruptCallback.cpp b/src/InterruptCallback.cpp index 67e7b4bd..9a28c206 100644 --- a/src/InterruptCallback.cpp +++ b/src/InterruptCallback.cpp @@ -22,8 +22,9 @@ PUSH_NO_WARNINGS POP_NO_WARNINGS #elif defined(ARDUINO_ARCH_RP2040) // Earle Philhower arduino-pico core exposes the Pico SDK alarm API. - // add_repeating_timer_us() fires a hardware alarm callback at a precise - // interval without relying on FreeRTOS or a second core. + // add_repeating_timer_us() fires a hardware-alarm callback at a precise interval in + // interrupt context, like the AVR timers. (The ESP32 port instead steps from a FreeRTOS + // task; this core has no RTOS at all, and no second core needs to be dedicated.) #include #else #error Unrecognized board selected. Either implement interrupt code or define the board here. From baab6f6cd16aa4a2124c965e47985bb22361342b Mon Sep 17 00:00:00 2001 From: Lutz Date: Sat, 17 Oct 2026 10:32:30 -0700 Subject: [PATCH 26/26] fix(rp2040): address PR review feedback - SSD1306 display header: provide no-op PUSH/POP_NO_WARNINGS fallbacks (mirroring inc/Globals.hpp) so Arduino IDE builds, which lack the PlatformIO -include of macros/gcc/Macros.hpp, can still compile it. - updateInfoDisplay(): declare isSlewingAny inside the RP2040 arm; it was unused (and -Werror=unused-variable under -Wall) on display-enabled AVR/ESP32 configs. - Utility logv(): restore flush() on all non-RP2040 platforms so AVR/ESP32 logging behavior is unchanged; only the arduino-pico USB CDC path skips it (CDC flush can stall without a reader). - Example config: fix AZ_CIRCUMFERENCE pi typo; align the stepper interval with the 5 kHz PR default (10 kHz noted as possible but unverified). - Docs: drop the nonexistent USE_AUTOHOME flag reference. - .gitignore: remove duplicated negation lines from the develop merge. Co-Authored-By: Claude Code --- .gitignore | 3 --- Example_Configuration_local_rp2040_skr_pico.hpp | 8 +++++--- docs/RP2040-WIRING.md | 4 ++-- src/Mount.cpp | 5 ++--- src/SSD1306_128x64_Display.hpp | 12 +++++++++++- src/Utility.cpp | 6 ++++++ 6 files changed, 26 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index 642b3996..b0686c2e 100644 --- a/.gitignore +++ b/.gitignore @@ -14,8 +14,5 @@ Configuration_local* !Configuration_local_examples/* MeadeToWikiOutput.txt -!Configuration_local_examples/ -!Configuration_local_examples/* - # macOS **/.DS_Store diff --git a/Example_Configuration_local_rp2040_skr_pico.hpp b/Example_Configuration_local_rp2040_skr_pico.hpp index e830321c..edd4f73d 100644 --- a/Example_Configuration_local_rp2040_skr_pico.hpp +++ b/Example_Configuration_local_rp2040_skr_pico.hpp @@ -37,8 +37,10 @@ #define INFO_DISPLAY_MIRRORED 0 // ── Stepper control interval ───────────────────────────────────────────────── -// The RP2040 can handle a 10kHz stepper timer -#define STEPPER_CONTROL_INTERVAL_MS 0.1f // 10 kHz +// 5 kHz is the RP2040 default (see Configuration_adv.hpp) and the bench-verified +// rate. The RP2040 can also handle 10 kHz if you need faster step generation +// (set 0.1f), but that is not part of the verified baseline. +#define STEPPER_CONTROL_INTERVAL_MS 0.2f // 5 kHz // ── Stepper motor types ─────────────────────────────────────────────────────── #define RA_STEPPER_TYPE STEPPER_TYPE_ENABLED @@ -95,7 +97,7 @@ #define AZ_MOTOR_HOLD_SETTING 15 #define AZ_PULLEY_TEETH 20 #define AZ_ROD_PITCH 1.0f // mm per full rev of stepper -#define AZ_CIRCUMFERENCE (115 * 2 * 3.1515927) +#define AZ_CIRCUMFERENCE (115 * 2 * 3.1415927) #define AZIMUTH_STEPS_PER_REV (AZ_CIRCUMFERENCE / AZ_ROD_PITCH * AZ_STEPPER_SPR * AZ_MICROSTEPPING) // Steps needed to turn AZ 360deg #define AZ_INVERT_DIR 1 diff --git a/docs/RP2040-WIRING.md b/docs/RP2040-WIRING.md index 78cddf01..f9c0ea23 100644 --- a/docs/RP2040-WIRING.md +++ b/docs/RP2040-WIRING.md @@ -158,8 +158,8 @@ The FAN1 header is switched by a MOSFET on GP17 and carries the VIN rail ## Not available by default on RP2040 -- **StallGuard driver autohome** (`USE_AUTOHOME`) - not supported on these - boards; use Hall sensor homing instead (the DIAG outputs are unused) +- **StallGuard driver autohome** - not implemented in the OAT firmware on any + platform; use Hall sensor homing instead (the DIAG outputs are unused) - **LCD menu display** - `DISPLAY_TYPE` must be `DISPLAY_TYPE_NONE` (enforced at compile time) - **Gyro auto-leveling** - `USE_GYRO_LEVEL` must be 0 diff --git a/src/Mount.cpp b/src/Mount.cpp index b2911d5c..db551328 100644 --- a/src/Mount.cpp +++ b/src/Mount.cpp @@ -3405,11 +3405,10 @@ void Mount::updateInfoDisplay() // timeout, causing ASCOM errors. // We will update at 30Hz when idle, 5Hz when slewing one axis and skip updates when slewing both. - const bool isSlewingAny = (slewStatus() & (SLEWING_DEC | SLEWING_RA)) != 0; - int refreshRateHz = 30; #if defined(ARDUINO_ARCH_RP2040) - refreshRateHz = isSlewingAny ? 15 : 30; + const bool isSlewingAny = (slewStatus() & (SLEWING_DEC | SLEWING_RA)) != 0; + refreshRateHz = isSlewingAny ? 15 : 30; #else const bool isSlewingRAandDEC = (slewStatus() & (SLEWING_DEC | SLEWING_RA)) == (SLEWING_DEC | SLEWING_RA); if (isSlewingRAandDEC) diff --git a/src/SSD1306_128x64_Display.hpp b/src/SSD1306_128x64_Display.hpp index 2ff75b79..6e59daf6 100644 --- a/src/SSD1306_128x64_Display.hpp +++ b/src/SSD1306_128x64_Display.hpp @@ -1,7 +1,17 @@ #pragma once -PUSH_NO_WARNINGS +// In PlatformIO builds the real pragma wrappers come from macros/gcc/Macros.hpp, +// which is force-included via the -include build flag. Arduino IDE builds have no +// such flag, and this header can be the first to use the macros (SSD1306_128x64_Display.cpp +// includes it directly), so provide the same no-op fallbacks as inc/Globals.hpp. +#if !defined(PUSH_NO_WARNINGS) + #define PUSH_NO_WARNINGS ; +#endif +#if !defined(POP_NO_WARNINGS) + #define POP_NO_WARNINGS ; +#endif // The arduino-pico core headers (the Arduino.h chain) and the OLED library are not // warning-clean under our strict flag set (-Wshadow). +PUSH_NO_WARNINGS #include #include "SSD1306Wire.h" POP_NO_WARNINGS diff --git a/src/Utility.cpp b/src/Utility.cpp index 69739ee7..16248a1d 100644 --- a/src/Utility.cpp +++ b/src/Utility.cpp @@ -424,6 +424,12 @@ void logv(int levelFlags, String input, ...) line += formatArg(input.c_str(), argp); line += "\n"; DEBUG_SERIAL_PORT.print(line); + #if !defined(ARDUINO_ARCH_RP2040) + // UART outputs drain from a ring buffer; flush so the tail of the log is not + // lost if the firmware crashes right after logging (matters for AVR debugging). + // On RP2040 the port is USB CDC, where flush() can stall without a reader. + DEBUG_SERIAL_PORT.flush(); + #endif #endif lastLog = now; va_end(argp);