From b675d985c9993e45f2f4fecd2972d9f8ecfef0d7 Mon Sep 17 00:00:00 2001 From: Michele Bigi Date: Wed, 19 Aug 2026 23:15:49 +0200 Subject: [PATCH] BT1035: fix SYS_CTRL power-on sequencing per Feasycom programming guide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Feasycom BT1035 programming user guide's own pin table (§2.2, pin 34 SYS_CTRL) reads "Delay 100ms, pull high" -- the previous reset sequence here asserted SYS_CTRL high at the very same instant as RESET, with zero lead-in delay, racing the module's own documented power-on requirement (the datasheet's §4.7 separately confirms SYS_CTRL must be asserted >20ms before internal regulators even start powering up). Rewrote resetAndInitOnce() to hold both pins low for a 100ms lead-in matching the guide exactly, then bring SYS_CTRL high, then an extra 50ms settle margin before releasing RESET into a module that's had a chance to actually power up first. This is verified correct against the manufacturer's own documented timing and is worth keeping regardless of its effect on any one symptom, but it does NOT fully explain this project's intermittent BT1035 boot failures ("no spontaneous UART bytes after hardware reset"): a deep investigation session confirmed the same failure still occurs, at the same rate, across genuine physical power cycles (not just soft resets) with this fix applied, extended UART listen windows (tested up to 10s vs the normal 3.5s), and independently schematic-verified-correct GPIO pin assignments, UART TX/RX wiring, AT command bytes, and shared 3.3V regulator sizing. Unlike the Si4684 ARG1-offset bug earlier this session -- which failed 100% of the time, deterministically, from a real code defect -- this failure is non-deterministic across identical power-on sequences with identical code, which does not match a firmware logic-bug signature. Root cause remains open; see docs/si4684-rf-investigation-report.md. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_0178rASQ6ZETPMUamvpoR2KR --- .../drivers/bt1035/src/Bt1035Driver.cpp | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Software/components/drivers/bt1035/src/Bt1035Driver.cpp b/Software/components/drivers/bt1035/src/Bt1035Driver.cpp index 86274a2..acc40c0 100644 --- a/Software/components/drivers/bt1035/src/Bt1035Driver.cpp +++ b/Software/components/drivers/bt1035/src/Bt1035Driver.cpp @@ -38,6 +38,12 @@ constexpr int kUartTxBuffer = 256; constexpr int kResponseTimeoutMs = 2000; constexpr int kPostResetMs = 500; constexpr int kPostUartMs = 100; +/** Feasycom BT1035 programming user guide §2.2 (pin 34 SYS_CTRL): "Delay + * 100ms, pull high". */ +constexpr int kSysCtlLeadInMs = 100; +/** Margin beyond the datasheet's own >20ms SYS_CTRL-assertion-to-power-up + * minimum (§4.7), for regulator/crystal settling before RESET releases. */ +constexpr int kSysCtlSettleMs = 50; /** Observed intermittently: the module sometimes needs a second RESET# * pulse to come up (power-up timing jitter between cold/warm boots) — * a single attempt with no retry was found to explain sporadic total @@ -913,9 +919,20 @@ std::expected Bt1035Driver::runInitSequence() std::expected Bt1035Driver::resetAndInitOnce() { - gpio_set_level(static_cast(pins_.sysCtlGpio), 1); + // Feasycom BT1035 programming user guide §2.2, pin 34 SYS_CTRL: + // "Delay 100ms, pull high" — the datasheet's own OFF-state timing spec + // (§4.7) says SYS_CTRL must be asserted >20ms before the internal + // regulators start powering up at all, so pulling it high with no + // lead-in delay (the previous sequence here) races the chip's own + // power-on requirement. Held low with RESET already asserted, then a + // 100ms lead-in exactly matching the guide, then SYS_CTRL high, then + // extra settle time before releasing RESET into a chip that's had a + // chance to actually power up first. + gpio_set_level(static_cast(pins_.sysCtlGpio), 0); gpio_set_level(static_cast(pins_.resetGpio), 0); - vTaskDelay(pdMS_TO_TICKS(100)); + vTaskDelay(pdMS_TO_TICKS(kSysCtlLeadInMs)); + gpio_set_level(static_cast(pins_.sysCtlGpio), 1); + vTaskDelay(pdMS_TO_TICKS(kSysCtlSettleMs)); gpio_set_level(static_cast(pins_.resetGpio), 1); vTaskDelay(pdMS_TO_TICKS(kPostResetMs));