From 142d3bc2d622f58569751781cb9e774a30ee4ab3 Mon Sep 17 00:00:00 2001 From: Wessel Nieboer Date: Fri, 6 Mar 2026 10:40:35 +0100 Subject: [PATCH 1/2] nRF52 BLE: wait for LFXO crystal before enabling SoftDevice The Adafruit framework starts the LFXO in init() but never waits for EVENTS_LFCLKSTARTED. On first boot the filesystem format (~600ms of page erases) gives the crystal time to stabilize. On subsequent boots only quick mounts happen, so sd_softdevice_enable() inside Bluefruit.begin() can be called while the crystal is still starting, which hangs indefinitely. Poll EVENTS_LFCLKSTARTED before Bluefruit.begin() so the wait is exact rather than a blind delay. fixes: #1780 --- src/helpers/nrf52/SerialBLEInterface.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/helpers/nrf52/SerialBLEInterface.cpp b/src/helpers/nrf52/SerialBLEInterface.cpp index 5648707e6a..76b8541bee 100644 --- a/src/helpers/nrf52/SerialBLEInterface.cpp +++ b/src/helpers/nrf52/SerialBLEInterface.cpp @@ -129,6 +129,15 @@ void SerialBLEInterface::begin(const char* prefix, char* name, uint32_t pin_code char charpin[20]; snprintf(charpin, sizeof(charpin), "%lu", (unsigned long)pin_code); + // Ensure LFXO crystal is fully started before enabling SoftDevice. + // The framework starts LFXO in init() but doesn't wait for it. + // On fast boots (filesystem already formatted), Bluefruit.begin() can + // be called before the crystal is stable, hanging sd_softdevice_enable(). + // See: https://github.com/meshcore-dev/MeshCore/issues/1780 + while (!NRF_CLOCK->EVENTS_LFCLKSTARTED) { + delay(1); + } + // If we want to control BLE LED ourselves, uncomment this: // Bluefruit.autoConnLed(false); Bluefruit.configPrphBandwidth(BANDWIDTH_MAX); From e715a4b8d5f1f1f45d86dc2ca170549d1c4ab310 Mon Sep 17 00:00:00 2001 From: Wessel Nieboer Date: Fri, 6 Mar 2026 14:24:21 +0100 Subject: [PATCH 2/2] Check if we use LFXO and guard with 2 second timeout for broken crystals --- src/helpers/nrf52/SerialBLEInterface.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/helpers/nrf52/SerialBLEInterface.cpp b/src/helpers/nrf52/SerialBLEInterface.cpp index 76b8541bee..0c31cb6f09 100644 --- a/src/helpers/nrf52/SerialBLEInterface.cpp +++ b/src/helpers/nrf52/SerialBLEInterface.cpp @@ -134,9 +134,18 @@ void SerialBLEInterface::begin(const char* prefix, char* name, uint32_t pin_code // On fast boots (filesystem already formatted), Bluefruit.begin() can // be called before the crystal is stable, hanging sd_softdevice_enable(). // See: https://github.com/meshcore-dev/MeshCore/issues/1780 - while (!NRF_CLOCK->EVENTS_LFCLKSTARTED) { - delay(1); +#ifdef USE_LFXO + { + uint32_t lfclk_start = millis(); + while (!NRF_CLOCK->EVENTS_LFCLKSTARTED) { + if (millis() - lfclk_start >= 2000) { + Serial.println("WARNING: LFXO crystal did not start within 2s — check 32.768kHz crystal"); + break; + } + delay(1); + } } +#endif // If we want to control BLE LED ourselves, uncomment this: // Bluefruit.autoConnLed(false);