Battery-powered WiFi module that extends a Raspberry Pi's serial bus (I2C, UART, SPI) over WiFi using MQTT. SX1276 LoRa 868 MHz transceiver supplements WiFi for long-range parallel operation. LiPo powered with USB-C charging (BQ24075), 3.3V LDO (MCP1700), ESP32-C6-MINI-1-N4 MCU.
Milestones
| Code | Title | Status | Target | Achieved | TC |
|---|---|---|---|---|---|
| MS-001 | Bring-up | marker | 2026-06-05 | — | 0 / 0 |
| MS-002 | Base Functions Verified | overdue / blocked | 2026-06-12 | — | 0 / 23 |
| MS-003 | WiFi Functionality Verified | overdue / blocked | 2026-06-19 | — | 0 / 5 |
| MS-004 | LoRa Functionality Verified | overdue / blocked | 2026-06-26 | — | 0 / 4 |
| MS-005 | Battery Functionality Verified | overdue / blocked | 2026-07-03 | — | 0 / 6 |
| MS-006 | Verification Wrap-Up | overdue / blocked | 2026-07-10 | — | 0 / 3 |
| MS-007 | Release | marker | 2026-07-17 | — | 0 / 0 |
Items (37)
| Code | Status | Severity | Kind | Title | Date |
|---|---|---|---|---|---|
| E-023 | open | blocking | issue | J3 external connector shorts 3V3 to GND when external device connected | 2026-06-08 |
| E-028 | open | blocking | issue | SX1276 rejects OPMODE writes to PLL-active modes (0x82–0x85) — RF subsystem not starting | 2026-06-09 |
| E-012 | open | warning | issue | USB-C connector EOL — R0 units modified, R1 to use 12401899E412A | 2026-06-05 |
| E-013 | open | warning | issue | BQ24075 EN1 incorrectly pulled HIGH by R1 → Standby mode, OUT disabled | 2026-06-05 |
| E-014 | open | warning | issue | USB-CDC flashing unreliable — COM3 intermittently unavailable on Windows | 2026-06-06 |
| E-015 | open | warning | notice | Brownout detector (BOD) disabled — must be configured before production | 2026-06-06 |
| E-016 | open | warning | issue | NVS provisioning use-after-free bug — fixed build not yet flashed | 2026-06-06 |
| E-017 | open | warning | issue | WiFi RF PLL calibration fails on warm reset — USB power cycle required | 2026-06-06 |
| E-021 | open | warning | issue | ADS7828 (U6) VCC decoupling cap C28 missing on A003460 — probable cause of erratic ADC readings | 2026-06-07 |
| E-022 | open | warning | issue | INA333 gain fixed at G≈2 — A2 first-stage output clamps at GND for low-side sensing at high gain | 2026-06-08 |
| E-026 | open | warning | notice | ASM: Pi operational SSID and password derived from unit serial/MAC — pending head of operations approval | 2026-06-08 |
| E-027 | open | warning | issue | Find suitable LiPo battery — max 35 × 34 × 6 mm | 2026-06-09 |
| E-030 | open | warning | issue | RTC drift ~3180 ppm slow — internal RC oscillator, no external 32.768 kHz crystal | 2026-06-12 |
| E-010 | open | info | concept | Accordion Wireless Serial Bus Bridge | 2026-06-05 |
| E-018 | open | info | decision | Two-bus I2C architecture: LP_I2C for internal peripherals, I2C0 for external MQTT bridge | 2026-06-06 |
| E-019 | open | info | decision | MQTT topic structure: beacon/<device_id>/<function>/<direction> | 2026-06-06 |
| E-020 | open | info | decision | Device identity: MAC-based temporary ID with NVS serial override via provisioning | 2026-06-06 |
| E-024 | open | info | decision | R1: Replace INA333 + ADS7828 with INA226 for battery current and voltage monitoring | 2026-06-08 |
| E-025 | open | info | concept | Raspberry Pi as local offline IoT hub with dual-AP provisioning for ESP32 devices | 2026-06-08 |
| E-029 | open | info | notice | Full BQ24075 charge cycle verified on A003460 — CC, CV, and termination confirmed | 2026-06-10 |
| E-032 | open | info | decision | Battery life target: ≥11 days at 1-minute wake interval (3.038 mA measured average current) | 2026-06-12 |
| E-033 | open | info | notice | BQ24075 charger (U1): the paired BAT pad (pin 3) and OUT pad (pin 11) are left unconnected — only one pad of each pair carries the battery … | 2026-06-14 |
| E-034 | open | info | notice | Beacon (ESH10000671 R0) — Probe design review COMPLETE. Analysis run 5: 23/23 checks addressed (100%), 71% with positive evidence, 29% hone… | 2026-06-14 |
| E-035 | open | info | notice | [CON-001] Trace cross-check — reconciling CON-001 against existing project records: (1) E-029 (full charge cycle verified on unit A003460)… | 2026-06-14 |
| E-036 | open | info | notice | Intent-grounded review pass (board 3) — re-ran the review against the Trace open-issue set, each tested vs the netlist (the FR-010 case in … | 2026-06-14 |
| E-037 | open | info | notice | U5 (PI4IOE5V6416ZDEX) exposed die pad — pin 25, named GND — is unconnected (single-point net `unconnected-(U5-GND-Pad25)`). The logic groun… | 2026-06-15 |
| E-001 | closed | info | decision | Bus pin assignments for ESP32-C6 | 2026-05-26 |
| E-002 | closed | info | decision | KiCad schematic sheet structure — 4 sheets | 2026-05-26 |
| E-003 | closed | info | decision | BQ24075T passive network configuration | 2026-05-26 |
| E-004 | closed | info | decision | PI4IOE5V6416ZDEX I2C address and port allocation | 2026-05-26 |
| E-005 | closed | info | decision | ADS7828 I2C address 0x48 | 2026-05-26 |
| E-006 | closed | info | decision | J_EXT connector pinout (AXK5S60047) — deviations from reference | 2026-05-26 |
| E-007 | closed | info | decision | UART0 TX/RX test access via 1×2 2.54 mm pin headers | 2026-05-26 |
| E-008 | closed | info | decision | Battery current sense — INA333 + 100 mΩ shunt + AO3407 PMOS power-gate | 2026-05-26 |
| E-009 | closed | info | decision | SX1276 32 MHz crystal — ECS-320-10-37B-CKY-TR3 for R0 prototype | 2026-05-26 |
| E-011 | closed | info | notice | C19 BOM deviation — 2u2 fitted instead of 4u7 (all R0 units) | 2026-06-05 |
| E-031 | closed | info | notice | Battery discharge test — A003460, deep sleep 1 min interval — test paused, partial results documented | 2026-06-12 |
Requirements
| Code | Status | Category | Title | Statement | Acceptance |
|---|---|---|---|---|---|
| REQ-001 | approved | Functional | Battery Charging | The device shall charge a single-cell LiPo battery via USB-C. Charge current shall be approximately 593 mA, set by a 1.5 kΩ ISET resistor on the BQ24075. | Battery charges from a USB-C 5V source; charge current measured at 580–610 mA. |
| REQ-002 | approved | Performance | Power Path Output | The BQ24075 SYS output shall provide approximately 4.7–4.9V (VBUS minus dropout) when USB-C is connected, serving as input to the 3.3V LDO. | SYS pin voltage measured at 4.7–4.9V with USB-C 5V connected. |
| REQ-004 | approved | Functional | Charge Status Indication | Charge status shall be indicated via the CHG and PG outputs of the BQ24075 during active charging and when charging is complete. | CHG pin asserted during charging; PG pin asserted when power good; status observable. |
| REQ-005 | approved | Mechanical | Battery Connector | The board shall provide a JST-PH 2.0mm 2-pin connector for connecting a single-cell LiPo battery. | JST-PH 2.0mm connector present; polarity marked; a standard LiPo battery connects without modification. |
| REQ-007 | approved | Functional | 3.3V Rail | The MCP1700T LDO shall output a regulated 3.3V supply rail, fed from the BQ24075 SYS output. Input and output decoupling capacitors shall be fitted. LDO quiescent current shall not exceed 4 µA. | 3.3V rail measured within ±2% under no-load and rated-load conditions. LDO quiescent current ≤ 4 µA verified. |
| REQ-011 | approved | Functional | Battery Voltage Monitoring | The battery voltage shall be monitored via a 1:2 voltage divider (2×1 MΩ resistors) connected to ADC channel 0. The divider shall be software-disconnectable to prevent quiescent drain during deep sleep. Quiescent drain when active shall not exceed 5 µA. | Battery monitoring net measures half of battery rail voltage. Divider disconnected in deep sleep. Quiescent drain ≤ 5 µA when enabled. |
| REQ-015 | approved | Functional | MCU Boot and USB Detection | The ESP32-C6-MINI-1-N4 shall boot successfully and be detectable over USB. A BOOT pin shall be accessible for entering USB bootloader mode for firmware flashing. | ESP32 boot messages visible on UART; device enumerated as USB device; BOOT pin forces bootloader when held low at reset. |
| REQ-016 | approved | Performance | MCU Supply Voltage | 3.3V shall be present at the MCU supply pin within the specified operating range of 3.0–3.6V. Decoupling capacitors (100 nF near VCC pads, 100 µF bulk) shall be fitted near the module. | 3.3V measured at MCU supply pin within 3.0–3.6V under all operating conditions. |
| REQ-017 | approved | Performance | Deep Sleep Current | Total board current in deep sleep mode shall not exceed 20 µA. The SX1276 shall enter sleep mode and the INA333 shall be power-gated during ESP32 deep sleep to meet this budget. | Total board current measured ≤ 20 µA in deep sleep with battery as only supply. |
| REQ-018 | approved | Functional | WiFi Connectivity | The device shall connect to a 2.4 GHz WiFi 6 (802.11ax) network. | Device successfully associates to a 2.4 GHz access point; ping successful. |
| REQ-019 | approved | Functional | BLE Advertisement | The device shall support BLE 5.0 and advertise over Bluetooth. | BLE advertisement detected by a scanning device. |
| REQ-020 | approved | Interface | External Serial Bus Connector (J3) | The external serial bus connector (J3) shall expose I2C, UART, SPI, 3.3V, VREF (2.5V), 5V, and GND. All bus signals and power rails shall be accessible for connecting external modules or test equipment. | I2C, UART, and SPI signals verified on J3; 3.3V measures 3.30V ± 3%; VREF measures 2.50V ± 0.1%; 5V measures 5.0V ± 5% on J3. |
| REQ-021 | approved | Interface | External UART | UART shall be accessible on the external serial bus connector. | UART TX and RX signals present on external connector; loopback test passes. |
| REQ-022 | approved | Interface | External SPI Bus | SPI shall be accessible on the external serial bus connector. | SPI MOSI, MISO, SCK, and CS signals present on external connector; loopback test passes. |
| REQ-024 | approved | Functional | USB-C Power Supply | The device shall be supplied and charged via a 5V USB-C connection. The device shall operate from USB alone without a battery connected. | Device powers on and operates normally from USB-C 5V supply only, with no battery connected. |
| REQ-025 | approved | Safety | ESD Protection | The USB-C VBUS input shall be protected against electrostatic discharge. | ESD protection component present on VBUS net; passes inspection. |
| REQ-026 | approved | Mechanical | RF Isolation | The LoRa RF section shall be positioned away from the ESP32 antenna, with the ESP32 antenna keep-out zone observed. The battery monitor divider shall be routed away from the RF area. | PCB layout inspection confirms RF section separated from ESP32 antenna; keep-out zone clear; battery divider routing verified away from RF area. |
| REQ-030 | approved | Mechanical | Test Point Access | Test points shall be provided on 3.3V, GND, UART TX/RX, BOOT, and RESET for bring-up and debug. | All specified test points present and accessible with a probe during testing. |
| REQ-031 | approved | Functional | MQTT Communication | The device shall publish and receive messages over MQTT with a Raspberry Pi broker over WiFi. | Device subscribes and publishes to at least one MQTT topic; messages received by broker on Raspberry Pi. |
| REQ-033 | approved | Functional | Sleep Mode Control | The device shall support Sleep ON and Sleep OFF operating modes. In Sleep ON mode, the device shall wake periodically at a configurable interval persisted in non-volatile storage. | Device enters deep sleep and wakes at configured interval; sleep interval survives power cycle. |
| REQ-034 | approved | Performance | Wake-to-Transmit Time | The device shall wake from deep sleep and transmit the first MQTT message within 500 ms, using a static IP configuration to avoid DHCP delay. | Time from wake-up to first MQTT publish measured ≤ 500 ms. |
| REQ-035 | approved | Performance | Battery Runtime | The device shall achieve ≥ 7 days runtime at a 10 s wake interval, and ≥ 45 days runtime at a 30 s wake interval, on a suitable single-cell LiPo battery. | Runtime budget calculation verified; prototype runtime test or power profile measurement confirms targets. |
| REQ-037 | approved | Functional | GPIO Expander Presence | The PI4IOE5V6416 GPIO expander shall be found at its expected I2C address. GPIO outputs shall be usable for external module control signals. The INT output shall be connected to IO22 for MCU wake-from-sleep. Supply decoupling (100 nF) shall be fitted. | I2C scan returns expected address for PI4IOE5V6416; GPIO output toggling verified; INT line connected to IO22. |
| REQ-041 | approved | Functional | System Monitor Presence | The ADS7828 12-bit 8-channel I2C ADC shall be found at its expected I2C address. Remaining ADC channels beyond CH0 shall be available for expansion. Supply decoupling and VREF from REF3425 shall be fitted. | I2C scan returns expected address for ADS7828; CH0 reads battery voltage; remaining channels accessible. |
| REQ-046 | approved | Functional | Battery Supply | It shall be verified that a LiPo battery supplies the battery rail voltage when USB-C is not connected. | Battery rail voltage present and within expected range when powered by LiPo only, with USB-C disconnected. |
| REQ-047 | approved | Functional | Power Source Selection | USB-C supply shall be prioritised over battery when both are connected. Simultaneous charging and system operation shall be supported. | With USB-C and battery both connected, system runs from USB-C while battery charges simultaneously. |
| REQ-050 | approved | Functional | LoRa Transceiver Presence | The SX1276 LoRa 868 MHz transceiver shall be accessible over SPI and respond to register reads. An SMA connector with 50 Ω matched trace shall be provided for antenna connection. | SX1276 register read via SPI returns expected device ID; SMA connector present on PCB. |
| REQ-051 | approved | Performance | RF Supply Rail | The filtered RF supply rail shall be correctly generated from 3.3V through a ferrite bead and be present at the transceiver RF power pin. | RF supply rail voltage measured at transceiver RF power pin; level within expected range. |
| REQ-052 | approved | Performance | Transceiver Supply Voltage | 3.3V shall be present on all transceiver voltage supply pins. | 3.3V measured on all SX1276 VCC supply pins. |
| REQ-053 | approved | Performance | Transceiver Clock | The transceiver crystal oscillator shall start up and oscillate at the expected frequency. | Oscillator signal observed at expected frequency after power-on. |
| REQ-057 | approved | Functional | LoRa and WiFi Concurrent Operation | LoRa and WiFi shall operate concurrently without mutual interference. | LoRa packet received while WiFi connection active; no degradation in either link. |
| REQ-058 | approved | Performance | Voltage Reference | The REF3425 shall output a 2.5000V precision voltage reference used as VREF for the ADS7828 ADC. | REF3425 output measured at 2.500V ±0.1% under rated load. |
| REQ-059 | approved | Functional | Battery Current Monitoring | Bidirectional battery current shall be measurable via the INA333 instrumentation amplifier. The INA333 shall be power-gated during deep sleep to preserve the deep sleep current budget. | INA333 output varies with charge/discharge current; device power-gated in deep sleep confirmed by current measurement. |
| REQ-061 | approved | Functional | Production Readiness | A BOM review shall be completed before production release to confirm component availability, pricing, and manufacturing readiness. | BOM review sign-off recorded; all components confirmed available in required quantities. |
Test Cases
| Code | Status | Category | Title / Signal | Target | Pass Criterion | Linked REQ |
|---|---|---|---|---|---|---|
| TC-A-00 | open | functional | ADC_GPIO | 2.1 ± 2% | Divider output measures 2.10V ± 2% with VBAT=4.2V | REQ-011 |
| TC-A-01 | open | functional | ADC_GPIO | 1.5 ± 2% | Divider output measures 1.50V ± 2% with VBAT=3.0V | REQ-011 |
| TC-A-02 | open | functional | ADC_GPIO | 0 | No measurable current through divider when GPIO driven low in deep sleep | REQ-011 |
| TC-A-03 | open | functional | VBAT | 10 | Total board current ≤ 20 µA in deep sleep with divider off at VBAT=3.7V | REQ-017 |
| TC-A-04 | pass | functional | VREF | 2.5 ± 0.05% | REF3425 output measures 2.500V ± 0.05% at VREF net (ADS7828 VREF pin) | REQ-058 |
| TC-A-05 | open | functional | INA333_OUT | — | INA333 output varies measurably with charge and discharge current; INA333 supply confirmed off (≤ 1 µA contribution) in deep sleep mode. | REQ-059 |
| TC-B-00 | open | functional | BOM cost and production readiness review | — | BOM review completed; cost-effective alternatives evaluated; prototype-only parts substituted or confirmed; review record captured in DECISIONS.md | REQ-061 |
| TC-C-00 | open | functional | USB-C connector fit | — | USB-C cable inserts and locks correctly; VBUS present | REQ-024 |
| TC-C-01 | open | functional | JST-PH battery connector fit and polarity | — | JST-PH 2-pin battery cable inserts correctly; polarity correct; battery charges | REQ-005 |
| TC-C-02 | open | functional | 3V3 | 3.3 ± 3% | Connector pinout matches schematic; 3.3V measures 3.30V ± 3% on J3; VREF measures 2.50V ± 0.1% on J3; 5V measures 5.0V ± 5% on J3 | REQ-020 |
| TC-C-03 | open | Safety | USB-C VBUS ESD protection | — | ESD protection diode present and functional on VBUS line; no damage after USB connection | REQ-025 |
| TC-D-00 | pass | functional | ESP32 boot and UART output | — | ESP32 programmed successfully; serial output visible on UART0 after boot | REQ-015 |
| TC-D-01 | pass | functional | I2C scan — external connector | — | I2C device detected at expected address via external connector | REQ-020 |
| TC-D-02 | open | functional | UART loopback — external connector | — | Known data sent and received correctly through external UART connector at 115200 baud | REQ-021 |
| TC-D-03 | open | functional | SPI loopback — external connector | — | SPI device read/write verified through external SPI connector | REQ-021 |
| TC-L-00 | pass | functional | SX1276 SPI comms and register read | — | SX1276 responds to SPI read of register 0x42 (VERSION) with 0x12; chip selectable via IO4 NSS | REQ-050 |
| TC-L-01 | open | functional | SX1276 DIO0 interrupt routing | — | DIO0 rising edge triggers interrupt on ESP32 IO5 within 1 ms of TX-done or RX-done event | REQ-050 |
| TC-L-02 | open | functional | LoRa and WiFi concurrent operation | — | Device maintains WiFi association while transmitting LoRa packet; no packet loss or disconnection observed | REQ-057 |
| TC-L-03 | open | performance | XTAL | — | Oscillator signal observed on SX1276 XTAL pins at expected frequency after power-on; waveform stable within 1 ms of supply ramp. | REQ-053 |
| TC-L-04 | open | Electrical | SX1276 supply rail voltages — VCC_RF and VCC | — | 1. Probe each SX1276 supply pin (VCC_RF — RF amp supply; VCC — digital supply) individually against GND with a DMM. All pins must read **3.3 V ± 0.1 V**. 2. Check each rail for ripple with a scope (10× probe). AC component must be **≤ 50 mVpp**. Any rail exceeding 50 mVpp ripple is a fail. 3. If a separate DC-DC or LDO supplies the RF rail: confirm EN is driven HIGH and output is in regulation before the SX1276 reset is released. Pass: all supply pins present at 3.3 V ± 0.1 V, ripple ≤ 50 mVpp on all rails. | REQ-052 |
| TC-L-05 | open | Electrical | LORA_RESETn pin state and boot pulse | — | LORA_RESETn is driven by PI4IOE GPIO expander P10 (port 1, bit 0) via I2C. 1. **Static check**: Probe LORA_RESETn with a DMM while the device is powered and running (after boot completes). Must read **3.3 V (HIGH)**. If stuck LOW, the SX1276 is permanently held in reset — SPI still works with default register values, but all mode transitions fail. 2. **Boot pulse**: Trigger a reboot and observe LORA_RESETn on a scope. Expected waveform: pin goes **LOW for ~1 ms**, then returns **HIGH and remains HIGH**. Pass: pin is HIGH during normal operation; LOW pulse observed during reset sequence with clean return to HIGH. | REQ-050 |
| TC-L-06 | open | Electrical | SX1276 crystal XTA/XTB oscillation — amplitude, frequency and symmetry | — | Use a 10× scope probe. Note: XTA amplitude was previously measured at 520 mVpp — below the expected level and a disqualifier for reliable PLL operation on its own. | Check | Pass criterion | |-------|---------------| | Frequency (XTA or XTB) | 32.000 MHz ± 10 ppm | | Amplitude on XTA | ≥ 800 mVpp sine wave | | Amplitude on XTB | Similar to XTA, ~180° phase shift | | Symmetry | XTA and XTB amplitudes within ~20% of each other. Asymmetric loading → suspect a load cap issue | | Load capacitors | Confirm BOM value matches schematic — correct load caps for crystal (typically ~20 pF per pin) | | Crystal part | Confirm correct part fitted — right frequency, right package (ECS-320-10-37B-CKY-TR3 on R0) | Pass: all rows above satisfied. Frequency within tolerance, amplitude ≥ 800 mVpp, symmetric on both pins. | REQ-053 |
| TC-L-07 | open | Electrical | RF output matching network — component population and solder quality | — | Using the schematic, check every component in the RF output matching network (π-network: C1=10 pF, L1=15 nH, C2=10 pF from RFO or PA_BOOST pin toward the antenna connector). Inspect the PCB for: - Missing 0402/0201 passives in the RF path - Tombstoned or rotated components - Cold or bridged solder joints on any RF passives - Any copper fill, via, or trace encroaching on the SX1276 antenna keepout zone or crystal keepout zone Pass: all components populated with correct values and orientation, no cold joints, no keepout violations. | REQ-050 |
| TC-L-08 | open | Mechanical | SX1276 QFN28 solder joint and thermal pad inspection | — | Inspect the SX1276 QFN28 solder joints under magnification (or X-ray if available). Key risk: the exposed thermal pad on the bottom of the QFN (GND). If not properly soldered, the chip may be floating on GND — this degrades supply decoupling and RF circuitry even if digital/SPI function appears normal. Check: - All peripheral QFN pads: adequate fillet, no bridges, no cold joints - Thermal pad: ideally confirmed by X-ray; visually check for any sign of package lifting or poor wetting at the perimeter Pass: no visible solder defects on peripheral pads; thermal pad solder quality confirmed acceptable (X-ray preferred, visual inspection acceptable if X-ray unavailable). | REQ-050 |
| TC-L-09 | open | Electrical | DIO0 (IO5) passive state check | — | Probe the DIO0 line (SX1276 DIO0 → ESP32-C6 IO5) with a DMM while the device is powered and idle (no TX/RX in progress). Expected: **~0 V** (LOW). No interrupt is being generated at rest, so the pin should be low. Note: a stuck HIGH on DIO0 would indicate a falsely-asserted interrupt. This would not cause mode transition failures, but could interfere with TX/RX completion handling once PLL issues are resolved. Pass: DIO0 reads ~0 V at rest. | REQ-050 |
| TC-M-00 | open | Mechanical | Visual inspection | — | No manufacturing defects, solder quality acceptable, all components correctly placed | REQ-026 |
| TC-M-01 | open | Mechanical | Antenna keep-out zone | — | No copper pour or traces under ESP32-C6-MINI-1 antenna area per datasheet keep-out zone | REQ-026 |
| TC-M-02 | open | Mechanical | VCC | 3 | 100 nF decoupling cap within 3 mm of ESP32 VCC pads | REQ-016 |
| TC-M-03 | pass | Mechanical | Test point access verification | — | All 6 test points present and accessible: 3.3V, GND, UART TX, UART RX, BOOT, RESET | REQ-030 |
| TC-P-00 | pass | functional | VBUS | 5 ± 5% | VBUS measures 5.0V ± 0.25V at charge IC input when USB-C 5V source connected | REQ-024 |
| TC-P-01 | pass | functional | VBAT | 593 ± 10% | Charge current ≤ 650 mA during CC phase with USB-C 5V and LiPo connected | REQ-003 |
| TC-P-02 | pass | functional | Charge status LED | — | CHG LED on during charge; PG LED on when VBUS present | REQ-004 |
| TC-P-03 | pass | functional | 3V3 | 3.3 ± 3% | 3.3V rail measures within ±3% at no load with VBAT=4.2V | REQ-007 |
| TC-P-04 | open | functional | 3V3 | 3.3 ± 3% | 3.3V rail measures within ±3% at no load with VBAT=3.0V | REQ-007 |
| TC-P-05 | open | functional | 3V3 | 3.3 ± 5% | 3.3V rail within ±5% with ESP32 in active WiFi TX mode at VBAT=3.7V | REQ-007 |
| TC-P-06 | open | functional | LDO_IN | 4 | LDO input current ≤ 4 µA with ESP32 in deep sleep and no load at VBAT=3.7V | REQ-007 |
| TC-P-07 | pass | functional | VBAT | — | Battery rail voltage present and within expected LiPo range (3.0–4.2V) with USB-C disconnected and LiPo connected. | REQ-046 |
| TC-P-08 | pass | performance | RF_VCC | 3.3 ± 5% | RF supply rail measured at SX1276 RF power pin; voltage within expected range derived from 3.3V across ferrite bead (≥ 3.0V, ≤ 3.3V). | REQ-051 |
| TC-P-09 | open | performance | SX1276_VCC | 3.3 ± 5% | 3.3V measured on all SX1276 VCC supply pins within ±5%. | REQ-052 |
| TC-P-10 | pass | functional | SYS | 4.8 ± 2% | BQ24075 SYS output measured at C3 in range 4.7–4.9V with USB-C 5V connected (or bench PSU at 5V on VBUS) | REQ-002 |
| TC-P-11 | pass | functional | VBUS | — | Board powered from bench PSU at 5V with 100 mA current limit; current does not hit limit; measured value recorded as bring-up idle current baseline for the unit under test | REQ-016 |
| TC-S-00 | pass | functional | WiFi connection at 2.4 GHz | — | ESP32 connects to WiFi AP at 2.4 GHz; IP address assigned or static IP in use | REQ-031 |
| TC-S-01 | open | functional | BLE 5.0 advertisement | — | BLE advertising started; visible from phone/BLE scanner nearby | REQ-019 |
| TC-S-02 | pass | functional | MQTT publish to Raspberry Pi broker | — | Module wakes, connects to WiFi, publishes MQTT message; message received on RPi broker | REQ-031 |
| TC-S-03 | open | functional | Sleep mode toggle via MQTT | — | Both Sleep OFF and Sleep ON modes functional and switchable via MQTT command | REQ-033 |
| TC-S-04 | open | performance | wake_to_tx | 500 | Time from deep sleep wake to MQTT publish ≤ 500 ms with static IP configuration | REQ-034 |
| TC-S-05 | open | performance | VBAT | 4.8 | Average current ≤ 4.8 mA at 10 s wake interval over 10-minute measurement window at VBAT=3.7V | REQ-035 |
Coverage Matrix
| REQ | Title | Category | Coverage | Linked Test Cases |
|---|---|---|---|---|
| REQ-001 | Battery Charging | Functional | approved | TC-P-01, TC-P-02 |
| REQ-002 | Power Path Output | Performance | approved | TC-P-01, TC-P-02, TC-P-10 |
| REQ-004 | Charge Status Indication | Functional | approved | TC-P-02 |
| REQ-005 | Battery Connector | Mechanical | approved | TC-C-01 |
| REQ-007 | 3.3V Rail | Functional | approved | TC-P-03, TC-P-05, TC-P-06, TC-P-04 |
| REQ-011 | Battery Voltage Monitoring | Functional | approved | TC-A-00, TC-A-01, TC-A-02 |
| REQ-015 | MCU Boot and USB Detection | Functional | approved | TC-D-00 |
| REQ-016 | MCU Supply Voltage | Performance | approved | TC-D-00, TC-M-02, TC-M-00, TC-P-11 |
| REQ-017 | Deep Sleep Current | Performance | approved | TC-A-03, TC-P-06 |
| REQ-018 | WiFi Connectivity | Functional | approved | TC-S-00 |
| REQ-019 | BLE Advertisement | Functional | approved | TC-S-01 |
| REQ-020 | External Serial Bus Connector (J3) | Interface | approved | TC-D-01, TC-C-02 |
| REQ-021 | External UART | Interface | approved | TC-D-02, TC-D-03 |
| REQ-022 | External SPI Bus | Interface | approved | TC-D-03 |
| REQ-024 | USB-C Power Supply | Functional | approved | TC-C-00, TC-P-00, TC-P-11 |
| REQ-025 | ESD Protection | Safety | approved | TC-C-03, TC-P-00 |
| REQ-026 | RF Isolation | Mechanical | approved | TC-M-01, TC-M-00 |
| REQ-030 | Test Point Access | Mechanical | approved | TC-M-03 |
| REQ-031 | MQTT Communication | Functional | approved | TC-S-02, TC-S-00 |
| REQ-033 | Sleep Mode Control | Functional | approved | TC-S-03, TC-S-02 |
| REQ-034 | Wake-to-Transmit Time | Performance | approved | TC-S-04 |
| REQ-035 | Battery Runtime | Performance | approved | TC-S-05 |
| REQ-037 | GPIO Expander Presence | Functional | approved | TC-D-01 |
| REQ-041 | System Monitor Presence | Functional | approved | TC-D-01 |
| REQ-046 | Battery Supply | Functional | approved | TC-P-07 |
| REQ-047 | Power Source Selection | Functional | approved | TC-P-01 |
| REQ-050 | LoRa Transceiver Presence | Functional | approved | TC-L-05, TC-L-08, TC-L-09, TC-L-07, TC-L-01, TC-L-00 |
| REQ-051 | RF Supply Rail | Performance | approved | TC-P-08 |
| REQ-052 | Transceiver Supply Voltage | Performance | approved | TC-L-04, TC-P-09 |
| REQ-053 | Transceiver Clock | Performance | approved | TC-L-06, TC-L-03 |
| REQ-057 | LoRa and WiFi Concurrent Operation | Functional | approved | TC-L-02 |
| REQ-058 | Voltage Reference | Performance | approved | TC-A-04, TC-C-02 |
| REQ-059 | Battery Current Monitoring | Functional | approved | TC-A-05 |
| REQ-061 | Production Readiness | Functional | approved | TC-B-00 |
Trace Link Graph
■ Done ■ Partial ■ Not started ■ No test case
Verification Records
| Test Case | Result | Measured | Notes | Date |
|---|---|---|---|---|
| TC-M-03 | pass | 3.3164 V | TP1 = 3.3164V, TP2 = 3.3130V. Both within ±3%. UART TX, RX, BOOT, RESET test points deferred to firmware bring-up step. | 2026-06-05 |
| TC-P-00 | pass | 4.9734 V | Measured at C1 with bench PSU at 5V. | 2026-06-05 |
| TC-P-01 | pass | 578.8 mA | Full CC-CV charge cycle captured from charge_profile.txt + new_charge_profile.txt on serial A003460. CC phase: ibat ~578–581 mA (ADC-read; ~565–568 mA net after ~13 mA offset), vbat rising from 3.740 V to 4.142 V over ~25 min. CV phase: vbat clamped at ~4.142–4.169 V, ibat tapering from ~581 mA. Termination: ibat dropped to noise floor (13.2 mA) at uptime 1d 00:40:22; last measured charge current before cutoff was 68.4 mA (~55 mA net = C/10 of ~570 mA CC current, consistent with BQ24075 default ITERM). Total charge time from CC start to termination: ~4h 54 min. Post-termination resting vbat: 4.122 V decaying to ~4.100 V. Current readings subject to ADC offset (~13 mA); precise values deferred to R1 calibration. BQ24075 CC/CV/termination algorithm confirmed functional. | 2026-06-10 |
| TC-P-01 | pass | 513 mA | Peak charge current 513 mA with USB-C 5V and LiPo at ~4.0V. Passes ≤650 mA criterion. Below nominal 593 mA — likely battery already near CV crossover at 4.0V. ISET resistor not verified separately. | 2026-06-08 |
| TC-P-02 | pass | — | CHG LED on during charge. PG LED on with VBUS present. Both LEDs behave as specified. | 2026-06-08 |
| TC-P-03 | pass | 3.3162 V | Measured at C6 (U2 LDO output). | 2026-06-05 |
| TC-A-04 | pass | 2.4996 V | Measured at C12 (REF3425 output). 0.016% error. | 2026-06-05 |
| TC-D-00 | pass | — | ESP32-C6 booted successfully. USB-Serial/JTAG accessible (VID 303A PID 1001, COM3). esptool 5.3.0 chip_id confirmed ESP32-C6FH4 rev v0.2, 4MB flash, MAC 8c:fd:49:01:b0:24. UART debug output confirmed during firmware development sessions. | 2026-06-06 |
| TC-D-01 | pass | — | I2C scan via Accordion. Found 0x20 (U5 PI4IOE5V6416 GPIO expander) and 0x48 (U6 ADS7828 ADC). Both at expected addresses. | 2026-06-05 |
| TC-S-00 | pass | — | WiFi 6 (802.11ax) 2.4 GHz connected successfully. ESP32-C6 associated with AP, IP assigned. Mosquitto broker at 192.168.0.147:1884 reachable. Note: warm-reset triggers RF PLL calibration failure (pll_cal exceeds 2ms) — cold power cycle required. See E-014. | 2026-06-06 |
| TC-S-02 | pass | — | MQTT publish confirmed to Mosquitto at 192.168.0.147:1884. Heartbeat beacon/01b024/status every 30s and telemetry beacon/01b024/telemetry every 10s verified. I2C bridge cmd/rsp topics verified (error-case, no device on J_EXT). Provisioning topic also functional. ESP-IDF v5.4.1. | 2026-06-06 |
| TC-L-00 | pass | — | SX1276 version register 0x42 read via SPI2 → 0x12. Confirmed via ESP-IDF sx1276 component init. Firmware: ESP-IDF v5.4.1. | 2026-06-06 |
| TC-P-07 | pass | 4 V | VBAT measured ~4.0V with USB-C disconnected and LiPo connected. Within LiPo range 3.0–4.2V. | 2026-06-08 |
| TC-P-08 | pass | 3.3149 V | Measured at C19 (RF 3V3 rail, 2u2 deviation unit). No RF load active — negligible drop across ferrite bead at idle. Within ±5% of 3.3V nominal. | 2026-06-05 |
| TC-P-10 | pass | 4.9 V | After R1 removal. SYS rail confirmed at 4.90V. Board idle current 32.9mA with all rails active. | 2026-06-05 |
| TC-P-10 | fail | 0 V | 0V measured at C3. VBUS confirmed at 4.9734V on C1. SYS output not present. U1 (BQ24075) suspected. | 2026-06-05 |
| TC-P-11 | pass | 177.7 uA | Current did not hit 100 mA limit. Recorded as bring-up idle current baseline. | 2026-06-05 |
Concepts
Active exploration (2) — ideas still being shaped.
Hypothesis
A compact battery-powered ESP32-C6 module with WiFi 6, BLE 5.0, and LoRa 868 MHz can serve as a transparent wireless bridge for the Accordion / Host serial buses (I2C, UART, SPI), eliminating cable runs to remote or hard-to-reach sensors while preserving full backwards compatibility with the existing Accordion / Host.
The module connects to the host over WiFi using MQTT as the application-layer protocol. The remote end presents standard I2C, UART, and SPI interfaces to any connected device via a 60-pin J_EXT connector. LoRa 868 MHz operates simultaneously with WiFi — not as a fallback, but as a supplemental long-range link for infrastructure-free or beyond-WiFi-range deployments.
block-beta columns 3 RPi["Accordion / Host"] space:1 Module["Beacon"] space:1 WiFi["WiFi / MQTT"] space:1 space:3 space:1 LoRa["LoRa 868 MHz (supplemental)"] space:1 space:3 space:1 space:1 Sensor["Remote Sensor or Device (I2C/UART/SPI)"] RPi --> WiFi WiFi --> Module Module --> LoRa Module --> Sensor
Key operational modes:
- Sleep OFF — WiFi always on; acts as a transparent bus bridge
- Sleep ON — Deep sleep with configurable wake interval (NVS-persisted); wakes, publishes data over MQTT, returns to sleep. Target: ≤ 500 ms wake-to-publish using static IP cached in RTC memory.
Power architecture: LiPo 800–1000 mAh + USB-C (BQ24075 power path + MCP1700 3.3V LDO). Deep sleep target ≤ 20 µA total board. Runtime targets: ≥ 7 days at 10 s interval / ≥ 45 days at 30 s interval.
Device identity and serial number assignment:
Each device has a unique ID used in all MQTT topics (beacon/<device_id>/...). Identity is determined at boot by a two-stage lookup:
- Read NVS namespace
beacon, keyserial— if present, use the stored serial (formatA######, e.g.A003460) - If absent, derive a temporary ID from the last 3 bytes of the WiFi MAC address (e.g. MAC
8c:fd:49:01:b0:24→01b024)
Serial number is assigned over MQTT (provisioning command) and written to NVS. The device reboots after provisioning; from that point all topics use the serial number as device ID. This ties the MQTT identity to the physical unit serial number tracked in PLEASE. See E-020 for the provisioning decision.
Alternatives considered
| Alternative | Disposition |
|---|---|
| Bluetooth-only bridge | Rejected — short range, no MQTT infrastructure alignment |
| WiFi-only, no LoRa | Rejected — limits deployment to WiFi coverage area only |
| ESP32-C3 instead of C6 | Rejected — C6 adds WiFi 6 (better coexistence), native USB-CDC, more GPIOs |
| On-board solar charging circuit | Deferred — external solar-to-USB adapters supported via USB-C + BQ24075 natively; no board circuit needed |
| Direct GPIO for SX1276 RESET | Not possible — all direct GPIOs allocated; RESET routed via PI4IOE expander P10 (firmware must init I2C expander before asserting LoRa RESET) |
| Dedicated UART0 connector (R0) | Deferred — 1×2 pin headers DNP by default; populate only if USB-CDC proves unreliable at bring-up |
Open questions
- PA_BOOST matching network — π-network (C1=10 pF, L1=15 nH, C2=10 pF) defined for SX1276 at 868 MHz; needs VNA verification at bring-up to confirm impedance match and output power.
- USB-CDC reliability on R0 — Primary flashing/debug path. If unreliable, UART0 headers (J_UART_TX / J_UART_RX) can be soldered. R1 decision pending bring-up result.
- SX1276 crystal production BOM — R0 uses ECS-320-10-37B-CKY-TR3 (NDK NX2016SA unavailable at order time). NX2016SA noted as cost-effective production alternative — confirm availability at BOM review (REQ-061).
- Battery divider always-on drain in R0 — Divider is software-disconnectable via GPIO (REQ-011) but lacks a hardware switch. R0 drain ≈ 2.1 µA always-on. Deep sleep budget is still met (≤ 20 µA). Consider PMOS switch in R1 if budget needs tightening.
- MQTT topic structure and sleep control protocol — Resolved in firmware development. See E-019 (topic structure) and E-020 (device identity).
- J_EXT pins 16 and 18 deviation — These carry active signals (EXT_SHDNn, EXT_RESETn) where the reference Accordion product uses GND. Any mating board must be aware; a cable compatibility note is required for ecosystem documentation.
Next step
DVT firmware verification: Phase 2 (telemetry bench verification), Phase 3 (SX1276 LoRa TX/RX), provisioning verification after USB flash issue (E-014) resolved.
Hypothesis
A Raspberry Pi acts as a fully self-contained, offline IoT hub — hosting its own Wi-Fi access point and an MQTT broker. ESP32 devices (Accordion Beacon Modules) connect to the Pi's Wi-Fi and communicate via MQTT with no internet required. The cleanest architecture runs two simultaneous Wi-Fi networks per Pi (dual virtual AP) to separate provisioning from normal operation, enabling identical firmware across all ESP32 units.
Core RPi Stack
| Component | Technology | Notes |
|---|---|---|
| MQTT Broker | Mosquitto | Port 1883, runs as a service |
| Wi-Fi AP | hostapd + dnsmasq | Dual virtual AP via iw |
| Provisioning API | Simple HTTP server | e.g. Flask or Node.js |
| ESP32 firmware | Standard Wi-Fi lib | Connects, provisions, reconnects |
| Pi static IP | dhcpcd | Always 192.168.4.1 |
Recommended hardware: Raspberry Pi 4B or 3B+ for dual-AP stability. Pi Zero W can work but is less reliable for dual virtual AP mode.
The Problem: Multiple Pis, Same SSID
If several Pis broadcast the same SSID, ESP32 devices connect to the strongest signal — not necessarily the intended unit. This creates fleet ambiguity. None of the naive mitigations (TX power reduction, physical separation, unique SSID pre-flashed) are clean at scale.
Recommended Solution: Dual Virtual AP + Provisioning Flow
Run two Wi-Fi networks simultaneously per RPi:
Network 1 — Generic Setup Network (shared across all Pis)
- SSID:
IoT-Setup(identical on every Pi) - Purpose: Bootstrap / provisioning only; low TX power recommended
Network 2 — Operational Network (unique per Pi)
- SSID: derived from Pi serial/MAC (see ASM — pending head of operations approval)
- Purpose: Normal ESP32 MQTT operation after provisioning
Provisioning flow (with acknowledgement lock):
- ESP32 powers on with no stored operational credentials (or re-provisioning triggered)
- ESP32 connects to generic
IoT-Setupnetwork - ESP32 calls
GET 192.168.4.1/provision - Pi responds with operational credentials and a lock token:
{ "ssid": "Pi-Unit-7-Network", "pass": "abc123", "lock_token": "xyz" } - ESP32 saves credentials to flash and sends acknowledgement:
POST 192.168.4.1/provision/confirm { "lock_token": "xyz" } - Pi confirms lock. ESP32 is now bound to this Pi.
- ESP32 reconnects to the unique operational network.
The acknowledgement step prevents accidental or rogue-Pi binding — locking only occurs after explicit two-way confirmation.
ESP32 connection logic (normal boot):
- Has stored operational credentials → attempt connection to operational network
- Connected → normal MQTT operation
- Cannot connect after N retries → enter provisioning mode automatically
- No credentials stored → enter provisioning mode directly
Lost operational network (Pi replaced, out of range) naturally re-triggers provisioning — no separate recovery path needed.
Re-Provisioning Trigger (Hardware)
A dedicated test point on the PCB, held low during boot, forces the ESP32 to clear stored credentials and enter provisioning mode. To be added to R1 schematic. Existing R0 TPs should be reviewed for a suitable candidate (BOOT pin may be usable).
Alternatives Considered
- Single shared SSID across all Pis: Causes roaming ambiguity. Not viable for fleet use.
- Unique SSID pre-flashed per ESP32: Kills the "identical firmware" goal.
- Bluetooth provisioning: Higher firmware overhead; Wi-Fi-only is simpler given ESP32-C6 capabilities.
- Separate re-provisioning GPIO vs. network fallback: Redundant — roaming fallback already covers the recovery case. TP provides the manual override only.
Open Questions
Should the provisioning endpoint be authenticated?Resolved: Two-way lock acknowledgement added to provisioning flow.Re-provisioning trigger?Resolved: TP held low at boot + automatic fallback when operational network unreachable.- SSID/password derivation from Pi serial/MAC: Agreed in principle — pending approval from head of operations (see ASM).
Multi-Pi roaming fallback?Resolved: ESP32 always tries operational network first; falls back to provisioning mode if it cannot connect.
Next Steps
- Resolve SSID/password derivation scheme (pending head of operations sign-off — see ASM)
- Prototype dual-AP setup on RPi 4B (hostapd + dnsmasq config)
- Implement provisioning HTTP endpoint with two-way lock acknowledgement
- Define N (retry count) before fallback to provisioning mode
- Add re-provisioning TP to R1 schematic
- Test with ESH10000671 R0 (A003460) once E-023 (J3 short) is resolved
Issues
Symptom
Connecting an external device to J3 (external serial bus connector) causes the 3V3 rail to be shorted to GND. Observed on A003460 during TC-C-02 / REQ-020 verification.
Status
Blocker — root cause not yet investigated. Resolution deferred to a later session.
Suspected Area
- J3 pinout / schematic error (3V3 pin shorted to GND pin in connector layout)
- External device pulling 3V3 low via a low-impedance path
- PCB short between 3V3 and GND in the J3 connector area
- Incorrect connector pinout vs. mating cable wiring
Next Steps
- Verify J3 pinout against schematic — confirm 3V3 and GND assignments
- Measure resistance between 3V3 and GND at J3 with no device connected (isolate PCB short vs. device-induced)
- Measure resistance between 3V3 and GND on the external device connector
- If PCB short: inspect J3 solder joints and surrounding copper
- If device-induced: review mating connector wiring and device power input
Impact
REQ-020 (External Serial Bus Connector J3) and REQ-024 (USB-C Power Supply) cannot be fully verified until resolved. MS-002 (Base Functions Verified, target 2026-06-12) at risk if not resolved promptly.
Symptom
SPI reads and writes to all SX1276 config registers work. LoRa mode switch (FSK Sleep → LoRa Sleep → Standby) succeeds. However, any write to OPMODE for modes 0x82–0x85 (FSTX, TX, FSRX, RXContinuous — all PLL-active) is immediately rejected. The chip returns to Standby (0x81) on the next read. Firmware confirmed correct.
Root Cause Hypotheses (ranked)
- VCC_RF missing or undervolted — directly blocks PLL; chip protects itself
- LORA_RESETn stuck LOW — would produce exactly this symptom (SPI works, mode transitions fail)
- Crystal load cap wrong or missing — PLL cannot lock without stable XO
- RF matching network component missing/wrong value — prevents PLL lock
- QFN thermal pad not soldered — globally degrades the chip RF circuitry
Existing Finding
Crystal XTA amplitude measured at 520 mVpp — below the ~800 mVpp expected. This is a disqualifier on its own for reliable PLL operation. Whether both XTA and XTB are oscillating cleanly and symmetrically remains to be confirmed.
Diagnostic Test Cases Added
- TC-L-04: VCC_RF and VCC supply rail voltages
- TC-L-05: LORA_RESETn pin state and boot pulse verification
- TC-L-06: Crystal XTA/XTB amplitude and frequency (detailed)
- TC-L-07: RF output matching network component population and solder quality
- TC-L-08: SX1276 QFN thermal pad solder quality inspection
- TC-L-09: DIO0 (IO5) passive state check
Problem
The USB-C connector specified/fitted on the R0 PCB is no longer in production. An alternative connector was sourced but required mechanical modification to fit: support legs and shield pins were cut, and epoxy was applied to all four R0 units to restore mechanical grip.
Affected units: A003458, A003459, A003460, A003461 (all R0 builds)
R0 status
Connectors are fitted and epoxied. Functionally the connector should work for bring-up and DVT. Mechanical robustness is reduced — avoid repeated plug/unplug cycles and handle USB-C connections carefully during testing.
TC-C-00 (USB-C connector fit) should note the modification and assess whether the epoxied connector is acceptable for the purpose of bring-up verification.
R1 action
Replace J2 USB-C connector with 12401899E412A. Verify footprint compatibility with R1 layout before releasing gerbers.
Root cause
R1 is a pull-up resistor connected to EN1 (BQ24075 pin 6). With VBUS present, R1 pulls EN1 HIGH. EN2 is also pulled HIGH by design (RILIM mode). EN1=H + EN2=H = Standby mode → OUT disabled.
Intended state
| Pin | Intended | Via |
|---|---|---|
| EN2 (pin 5) | HIGH | Pull-up to VBUS (by design — selects RILIM mode) |
| EN1 (pin 6) | LOW | Internal 285 kΩ pull-down (no external resistor needed) |
R1 fix for R1 PCB
No schematic change required. R1 shall be marked No Mount (DNP) in the BOM. The footprint remains; the component is simply not populated.
R0 rework required
All four R0 units require R1 physically removed:
- A003458 — rework pending
- A003459 — rework pending
- A003460 — rework done, SYS confirmed at 4.90V ✅
- A003461 — rework pending
Symptom
The ESP32-C6 USB-Serial/JTAG interface (VID 303A PID 1001) stops enumerating on Windows after repeated USB power cycles. Device remains operational (MQTT heartbeats continue) but COM3 does not appear regardless of USB port or cable used.
History
- USB-CDC flashing worked reliably for multiple firmware sessions
- Issue began after repeated USB power cycles performed to work around the WiFi RF PLL calibration bug (E-014)
- Switching to a specific PC USB port briefly restored COM3; device was successfully reflashed once
- Later, USB enumeration stopped entirely — no VID 303A devices visible in Device Manager
- No Windows USB overcurrent events found in system event log
Probable cause
Windows USB host stack state corruption from repeated connect/disconnect cycles, compounded by the warm-reset RF PLL issue requiring frequent power cycles.
Resolution options (in priority order)
- Reboot PC — resets Windows USB host stack (resolved the issue once)
- Disable/enable USB Root Hubs in Device Manager
- Flash via UART (IO16/IO17 with USB-UART adapter) — bypasses USB-CDC entirely
- OTA update (Phase 4) — eliminates USB dependency for future firmware updates
Status
Open. Active development blocker for flashing fixed provisioning firmware.
Bug description
In the initial provisioning handler implementation, the handler reads serial_j->valuestring after calling cJSON_Delete(root). The cJSON_Delete call frees the entire JSON tree including all string values, so valuestring is a dangling pointer at the point of use. This is a use-after-free memory safety bug.
Impact
- May crash or corrupt memory on provisioning command receipt
- Provisioning firmware was flashed once; bug discovered during code review
- Device was provisioned once successfully (may have been lucky — behaviour is undefined after free)
Fix
Fix is written and built (REPO/build/beacon.bin). The fix ensures the serial string is copied to a local buffer before cJSON_Delete is called.
Status
Fixed build is ready but not yet flashed. Blocked by USB-CDC flashing issue (E-015). Flash and verify provisioning end-to-end once USB is restored.
Verification required after flash
- Flash fixed build via
SCRIPTS/flash.py - Send provisioning command:
mosquitto_pub -h 192.168.0.147 -p 1884 -t "beacon/01b024/provision" -m '{"serial":"A003460"}' - Confirm device reboots and topics change to
beacon/A003460/...
Symptom
After a software reset (esp_restart() or triggered by firmware flash via USB), the RF PLL calibration fails with:
pll_cal exceeds 2ms!!!
WiFi scan subsequently finds 0 access points. Device is non-functional on WiFi until a full power cycle.
Workaround (current)
Disconnect and reconnect USB-C after every firmware flash or software reset. This forces a full power-down and restores PLL calibration.
Impact
- High friction during development — every firmware flash requires a physical USB power cycle
- Provisioning via MQTT causes
esp_restart()which triggers the issue - Incompatible with OTA updates (OTA also requires restart) unless resolved first
Hypothesis
Crystal oscillator requires full power-down to re-stabilise after reset. Antenna keepout zone or crystal selection may be a contributing factor. Warm reset leaves RF circuitry in an intermediate state that blocks PLL lock.
Required investigation
- Check antenna keepout zone compliance on R0 PCB layout
- Verify crystal load capacitance (ECS-320-10-37B-CKY-TR3, CL=10 pF) against schematic
- Test with RF shield or known-good crystal to isolate RF path vs oscillator
- Check
CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGEin sdkconfig - Consider testing NDK NX2016SA crystal (alternative documented in E-010)
Status
Open. Workaround in place for development. Must be resolved before field deployment.
Observation
U6 (ADS7828EB/2K5, 8-channel 12-bit ADC, LP_I2C address 0x48) on unit A003460 is exhibiting erratic/incorrect readings. Visual inspection of the board revealed that C28 — the decoupling capacitor on U6's VCC power pin — is not mounted.
Probable cause
The ADS7828 requires proper supply decoupling for accurate conversions. Without C28, supply noise (from BQ24075 switching, WiFi TX bursts, or other sources) will couple directly into the ADC reference and supply rails, causing noisy or offset readings. This is a build/assembly defect on this unit.
Affected unit
- A003460 (only unit inspected; other R0 units not yet checked)
Impacted requirements and test cases
- REQ-011 (Battery Voltage Monitoring) — TC-A-00, TC-A-01, TC-A-02
- REQ-059 (Battery Current Monitoring) — TC-A-05
Recommended rework
- Solder C28 (100nF 0402, EGP10000641) on A003460
- Re-run TC-A-00, TC-A-01, TC-A-02, TC-A-05 after rework to confirm readings are nominal
- Inspect C28 on A003458, A003459, A003461 to rule out a systematic assembly issue
Root Cause
INA333 (VSSOP-8) is used for low-side battery shunt current measurement (100 mΩ shunt, inputs at 0–50 mV above GND). For G = 20.6 (RG = 5.1 kΩ), first-stage amplifier A2 must swing its output to approximately −65 mV to maintain its virtual short. On a single 3.3 V supply, A2 cannot swing below V− = GND and clamps at 0 V. Confirmed by INA333 datasheet §7.4.2: "the linear input range is limited by the output voltage swing of amplifiers A1 and A2."
Evidence — Pin Voltages at 100 mA Charge Current
| Pin | Net | Expected | Measured | |
|---|---|---|---|---|
| 1 (RG1) | RG | V_IN+ = 13 mV | 11 mV | ✓ |
| 2 (IN−) | Shunt− | 0 mV | 0 mV | ✓ |
| 3 (IN+) | Shunt+ | ~10 mV | 13 mV | ✓ |
| 4 (V−) | GND | 0 V | 0 V | ✓ |
| 5 (REF) | 1.22 V bias | 1.22 V | 1.225 V | ✓ |
| 6 (OUT) | ADC input | REF + G×V_diff | 1.249 V | — |
| 7 (V+) | 3.3 V | 3.3 V | 3.32 V | ✓ |
| 8 (RG2) | RG | V_IN− = 0 mV | 11 mV | ✗ |
Pin 8 should equal V_IN− = 0 mV (virtual short). Measured 11 mV matches the resistor-divider result when A2_out clamps at 0 V:
V_pin8 = V_IN+ × R_int / (R_int + RG)
= 13 mV × 50k / (50k + 10k) = 10.8 mV ≈ 11 mV ✓
G_eff = (V_OUT − V_REF) / V_diff = 24 mV / 13 mV = 1.85 (not 20.6).
Changing RG from 5.1 kΩ → 10 kΩ → 100 kΩ produced no measurable gain change — consistent with A2 clamped throughout; external RG is irrelevant once A2 is saturated.
Impact
Current measurement unreliable on R0 hardware. Firmware was already corrected to use G = 2.0f (from 20.6f), which partially compensates but does not restore full dynamic range or resolution.
R0 Workaround
Set RG = 0 Ω (short pins 1–8). G_eff = 2.0 (maximum achievable with A2 clamped). Keep firmware constant at 2.0f. Effective sensitivity: 5 mA/LSB at 12 bit with 100 mΩ shunt and VREF = 2.5 V.
R1 Fix
Replace INA333 + ADS7828 with INA226 (Texas Instruments, I²C 16-bit bidirectional current/power monitor). Designed specifically for single-supply low-side and high-side sensing. No external gain resistor; gain set by shunt value and internal 2.048 V reference. Eliminates first-stage output headroom constraint entirely. Compatible with existing LP_I2C bus (IO6/IO7, ESP32-C6).
Task
Identify and qualify a LiPo battery that fits within the mechanical envelope of the Beacon Module enclosure.
Dimensional Constraints
| Parameter | Max |
|---|---|
| Length | 35 mm |
| Width | 34 mm |
| Thickness | 6 mm |
Criteria
- Fits within the above envelope (hard constraint)
- Maximise capacity within the envelope
- Standard LiPo voltage: 3.7 V nominal / 4.2 V max
- JST-PH 2-pin connector (matches J1 on ESH10000671 R0)
- Verify polarity against J1 pinout before ordering
Candidate: LP503034
| Parameter | Value |
|---|---|
| Thickness | 5.0 mm ✓ (limit 6 mm) |
| Width | 30 mm ✓ (limit 34 mm) |
| Length | 34 mm ✓ (limit 35 mm) |
| Capacity | ~500 mAh (typical) |
| Voltage | 3.7 V nominal / 4.2 V max |
Fits the envelope on all three axes with margin on thickness and width.
Next Steps
- Identify a specific part number / supplier for LP503034 (Mouser, Digi-Key, RS, LCSC)
- Confirm JST-PH 2-pin connector and verify polarity against J1 pinout
- Select and add to component library and BOM
Finding
ESP32-C6 RTC (internal RC oscillator) runs approximately 3 180 ppm slow relative to wall time. Measured from deep sleep test on A003460, 2026-06-11 to 2026-06-12.
Measurement Data
| Sample | Real time | Uptime | Implied T0 |
|---|---|---|---|
| First beat | 2026-06-11 09:21:10 | 0d 01:06:11 | 08:14:59 |
| #1 | 2026-06-11 13:21:05 | 0d 05:05:27 | 08:15:38 |
| #2 | 2026-06-11 16:28:45 | 0d 08:12:29 | 08:16:16 |
| #3 | 2026-06-12 08:30:18 | 1d 00:10:54 | 08:19:24 |
Drift rate by segment:
| Segment | Real elapsed | Uptime elapsed | Slow by | Rate |
|---|---|---|---|---|
| First → #1 | 14 395 s | 14 356 s | 39 s | 2 710 ppm |
| #1 → #2 | 11 260 s | 11 222 s | 38 s | 3 375 ppm |
| #2 → #3 | 57 693 s | 57 505 s | 188 s | 3 260 ppm |
| Overall | 83 348 s | 83 083 s | 265 s | ~3 180 ppm |
Impact
- Each 60 s sleep cycle actually runs ~59.81 s
- Loses ~274 s (~4 min 35 s) per day against wall time
- Drift rate is stable across all measured segments
Root Cause
Internal 150 kHz RC oscillator used for RTC during deep sleep. No external 32.768 kHz crystal fitted on R0.
R1 Fix
Add external 32.768 kHz crystal on XTAL_32K_P/N pins. Expected drift: <50 ppm. Required if accurate sleep interval timing is needed for field deployment.
Decisions
GPIO assignments constrained by ESP32-C6-MINI-1-N4 fixed-function pins (UART0, USB) and available GPIO matrix pins. LP_I2C assigned to dedicated low-power capable pins (IO6/IO7). IO4 and IO5 originally reserved for JTAG (MTMS/MTDI) — reservation removed 2026-04-12; reassigned to SX1276 NSS and DIO0.
Trade-offs: IO9 (I2C0 SCL) is a boot strapping pin — I2C pull-up holds it high at boot (safe). IO15 (UART1 RX) is a strapping pin for JTAG source. All GPIOs fully allocated except IO23.
Logical separation of subsystems improves readability and parallel review. Power sheet is self-contained for electrical safety review. MCU sheet isolates digital complexity.
Trade-offs: Cross-sheet signals require KiCad hierarchical labels. USB D-/D+ route from Power sheet to MCU sheet. LP_I2C routes from MCU sheet to On-board Peripherals sheet.
ISET and ILIM share 1.5kΩ value for BOM consolidation. TMR=56kΩ gives ~7h fast-charge timer adequate for LiPo cells. NTC thermistor function disabled — divider holds TS at valid level to prevent fault.
Trade-offs: ISET=1.5kΩ → ~593 mA charge current → ~0.77W dissipation on BQ24075; thermal pad copper pour required; BQ24075 TREG will throttle if die overheats. SYSOFF must not be pulled to VBUS. CE must not be pulled to VBUS.
Address 0x20 selected (no conflict with ADS7828 at 0x48). All 6 connector signals grouped on Port 0 for single-register read. LORA_RESETn on P10 (Port 1) is isolated from connector signals.
Trade-offs: RESET pin passively pulled to VCC via 10kΩ (no free MCU GPIO for soft-reset); I2C General Call Reset available as software alternative. INT pin is open-drain; 10kΩ pull-up to 3.3V; routed to IO22.
No conflict with PI4IOE5V6416 at 0x20. Simplest configuration — both address pins tied to GND.
Trade-offs: Address is fixed in hardware; cannot be changed without PCB rework.
Deviations required to expose REQ-038 module control signals (SHDNn, RESETn). No other adjacent NC pins available in that row. VREF exposed for potential mating board use.
Trade-offs: Mating cable/PCB MUST NOT connect pins 16 or 18 to GND — deviates from reference product. VREF (pin 7) limited drive; buffer required on mating board if load >5 mA.
If USB-CDC proves unreliable on prototype, headers allow a standard USB-serial adapter for UART0 access. Headers serve as test points when unpopulated.
Trade-offs: Prototype decision — revisit after board verification. If USB-CDC reliable: leave DNP in R1. If unreliable: populate and consider dedicated UART connector in R1. Partially satisfies REQ-030.
Bidirectional measurement needed to validate REQ-035/036 battery life estimates. ADS7828 CH1 was spare — no extra I2C device needed. PMOS power-gate preserves REQ-017 deep sleep budget (INA333 Iq=50µA otherwise exceeds 20µA limit). PI4IOE P06 was NC — zero cost.
Trade-offs: Adds R_SHUNT in battery series path (minor voltage drop at 600mA). Firmware must manage SHUNTn enable/disable around deep sleep entry/exit.
NDK NX2016SA unavailable at DigiKey/Mouser at time of BOM build. ECS ECX-1637B series is direct drop-in: 2016 4-pad footprint, CL=10pF, ESR≤50Ω, ±10ppm — all within SX1276 crystal requirements.
Trade-offs: ECS part used for prototype only. NX2016SA should be evaluated at production BOM review (REQ-061). No functional difference expected.
Decision
Two separate I2C buses are used simultaneously:
| Bus | Pins | Address range | Purpose |
|---|---|---|---|
| LP_I2C | IO6 (SDA) / IO7 (SCL) | 0x20, 0x48 | Internal on-board peripherals only |
| I2C0 | IO8 (SDA) / IO9 (SCL) | User-defined | External J_EXT connector — MQTT bridge target |
Internal LP_I2C devices (PI4IOE at 0x20, ADS7828 at 0x48) are accessed directly by firmware and are not exposed through the MQTT I2C bridge. All MQTT I2C bridge commands route exclusively to I2C0.
Rationale
- Isolates on-board peripherals from external commands — prevents accidental writes to PI4IOE (which controls power gating, LoRa reset, external reset/shutdown)
- LP_I2C is the ESP32-C6 low-power I2C peripheral — can be used independently of the main I2C0 driver
- Allows external I2C scanning without risk of conflicting with internal device addresses
Rejected alternative
Single I2C bus with address filtering — rejected because it requires firmware to maintain an address exclusion list and could still be bypassed by raw write commands.
Firmware implementation
pi4ioecomponent owns LP_I2C bus and creates the bus handle at initads7828component attaches to LP_I2C handle frompi4ioebus_i2ccomponent owns I2C0 and exposes it to the MQTT bridge handler inmain.c
Decision
MQTT topic structure is beacon/<device_id>/<function>/<direction>.
| Topic | Direction | Content |
|---|---|---|
beacon/<id>/status |
Device → host | Heartbeat every 30 s: {"status":"online","id":"...","uptime_s":N} |
beacon/<id>/telemetry |
Device → host | Power data every 10 s: {"vbat_v":X,"ibat_ma":Y,"uptime_s":N} |
beacon/<id>/i2c/cmd |
Host → device | I2C command: {"op":"read\|write\|write_read","addr":N,...} |
beacon/<id>/i2c/rsp |
Device → host | I2C response: {"status":"ok","data":[...]} or error |
beacon/<id>/provision |
Host → device | Serial assignment: {"serial":"A######"} |
<device_id> is unique per unit — MAC-based temporary ID or provisioned serial (see E-018).
Rationale
- Single namespace per device allows multiple Beacons on the same broker without topic conflicts
- Function/direction suffix aligns with common IoT MQTT conventions
- Flat
addrfield (decimal integer) avoids JSON hex parsing issues
Rejected alternatives
- Per-device subtopic hierarchy per peripheral — rejected as over-engineered for current use
- Binary protocol — rejected for debuggability (mosquitto_sub readable without tools)
Decision
Device identity is determined by a two-stage lookup on boot:
- Read NVS namespace
beacon, keyserial - If present: use stored serial (format
A######, e.g.A003460) as MQTT device ID - If absent: derive temporary ID from last 3 bytes of WiFi MAC
Example: MAC 8c:fd:49:01:b0:24 → temporary ID 01b024 → topics beacon/01b024/...
Provisioning flow
Host sends provisioning command → device writes serial to NVS → esp_restart() → topics change to beacon/A003460/.... Idempotent — re-sending overwrites and reboots.
Rationale
MAC-based fallback allows development without manual provisioning. NVS serial ties firmware identity to the PLEASE-tracked physical unit serial number.
Known limitation
esp_restart() triggers the WiFi RF PLL warm-reset bug (E-017). After provisioning, a USB power cycle is required to restore WiFi until E-017 is resolved.
Decision
For R1, remove INA333 (current sense amplifier) and ADS7828 (8-channel I²C ADC) from the design. Replace both with a single INA226 (Texas Instruments, I²C 16-bit bidirectional current/power monitor, EGP10001944).
Rationale
- E-022 root cause: INA333 cannot achieve high gain (G=20.6) with inputs near GND on a single 3.3V supply — A2 first-stage output clamps at 0V. Not fixable in layout; wrong part for this topology.
- ADS7828 was only used for two signals: battery current (INA333 output) and battery voltage (via resistor divider). Both are replaced by INA226 natively.
- INA226 advantages: bidirectional current sensing by design (confirmed), 16-bit resolution, integrated bus voltage measurement (VBAT on V_BUS pin, 0–36V range), I²C interface compatible with existing LP_I2C bus (IO6/IO7 on ESP32-C6), no external gain resistor, no external ADC reference needed.
- Resolution: 2.5 µV/LSB on ±81.92 mV shunt range → 25 µA/LSB with 100 mΩ shunt — significantly better than R0.
- Net result: two ICs removed, one added. Simpler schematic, smaller BOM, better measurement accuracy.
Power Gating — Deep Sleep Requirement
INA226 quiescent current: 420 µA max in active mode. Deep sleep budget (TC-A-03): ≤20 µA total board.
INA226 must be powered via a GPIO-controlled load switch and gated off before the ESP32 enters deep sleep. This is the same approach already specified for INA333 in TC-A-05 ("INA333 supply confirmed off, ≤1 µA contribution, in deep sleep"). The load switch requirement carries forward unchanged to R1 — no new design obligation, but must be explicitly included in the R1 schematic.
Firmware sequence: wake → enable load switch → wait for INA226 ready → read current + voltage → disable load switch → enter deep sleep.
Rejected Alternatives
- INA190A1 (G=25, EGP10001943): Fixes the common-mode limitation but has no REF pin — requires external biasing circuitry for bidirectional sensing. Added complexity without the integration benefit of INA226.
- INA333 with biased inputs: Would require raising common-mode voltage to ≥490 mV, requiring redesign of shunt placement. Adds complexity; INA226 is cleaner.
- Keep ADS7828 + fix INA333: Not feasible — INA333 is the wrong architecture for this application at the required gain.
Follow-up Actions
- Add INA226 to R1 schematic: IN+/IN− across 100 mΩ shunt (low-side); V_BUS → VBAT
- Place INA226 behind GPIO-controlled load switch (power gate for deep sleep)
- Set I²C address via A0/A1 pins — verify no conflict with existing LP_I2C devices
- Update firmware: replace ADS7828 + INA333 driver with INA226 I²C driver
- Update ibat_ma and vbat_mv calculations for INA226 register format
- REF3425 (2.5V reference) is retained in R1 BOM — required to supply VREF to external modules connecting via J3; not dependent on ADS7828 presence
Decision
Battery life target for ESH10000671 in deep sleep mode, based on directly measured average current:
| Wake interval | Battery | Capacity | Projected runtime | Target |
|---|---|---|---|---|
| 60 s (1 min) | 1100 mAh test battery (A003460) | 1100 mAh | ~15 days | ≥ 11 days |
| 60 s (1 min) | LP503034 (production candidate, E-027) | ~500 mAh | ~6.9 days | ≥ 5 days |
The test on A003460 (E-031) was run with a 1100 mAh battery. The production battery candidate (LP503034, E-027) is ~500 mAh and sized to fit the enclosure envelope (35×34×6 mm). Final target depends on which battery is selected for production.
Note: LP503034 at ~500 mAh yields only ~7 days projected — may be insufficient for field deployment if longer runtime is required. Consider a higher-capacity battery or enclosure resize for R1.
Basis
Average current: 3.038 mA — directly measured latent current draw at 1-minute wake interval on A003460 (supersedes voltage-slope estimate of ~1.6 mA from E-031).
- 1100 mAh / 3.038 mA = 362 h ≈ 15.1 days projected
- 500 mAh / 3.038 mA = 165 h ≈ 6.9 days projected
Targets set at ~25% margin below projection.
Rationale
- Direct current measurement is more reliable than the voltage-slope SoC estimate used previously
- 3.038 mA at 60 s interval breaks down as: deep sleep quiescent + WiFi/MQTT burst (~50–80 mA for ~3 s) averaged over 63 s cycle
- Active time currently ~3 s/cycle; reducing this (static IP RTC cache, faster MQTT handshake) is the primary lever for extending runtime
Assumptions and Caveats
- Full discharge not reached in E-031 — projection not yet validated against actual cutoff
- 1100 mAh test battery capacity not confirmed from datasheet; nominal value used
- LP503034 (~500 mAh) production candidate not yet sourced with confirmed part number (E-027 open)
Follow-up
- Confirm 1100 mAh test battery spec (actual rated capacity and part number)
- Decide production battery — LP503034 (~500 mAh) gives only ~7 days; may require larger cell or enclosure change
- Run full discharge test to cutoff to validate projected 15-day runtime
- Re-evaluate target once production battery is selected
- Re-measure average current after firmware optimisation (static IP, faster MQTT connect)
- Calibrated current measurement available after R1 INA226 integration (E-024)
Notices
Requirement REQ-046 ("Battery Supply") has no verifying test case. Add one with please_testcase_create and link it (verified_by).
Requirement REQ-052 ("Transceiver Supply Voltage") has no verifying test case. Add one with please_testcase_create and link it (verified_by).
Requirement REQ-051 ("RF Supply Rail") has no verifying test case. Add one with please_testcase_create and link it (verified_by).
Requirement REQ-053 ("Transceiver Clock") has no verifying test case. Add one with please_testcase_create and link it (verified_by).
Requirement REQ-059 ("Battery Current Monitoring") has no verifying test case. Add one with please_testcase_create and link it (verified_by).
C19 is populated with 2u2 on all four R0 units (A003458, A003459, A003460, A003461) instead of the BOM-specified 4u7. The 4u7 value was not available at build time.
C19 role: Bulk decoupling capacitor on the filtered RF supply rail (RF_VCC), placed after the ferrite bead that separates RF_VCC from the regular 3V3 rail. Provides low-frequency charge reservoir for the SX1276 RF power pin during TX bursts.
Assessment: The critical RF decoupling function is served by the smaller high-frequency caps (100 nF, 10 nF) which are unaffected. The 2u2 value halves the bulk reservoir but on a low-current RF rail this is unlikely to cause a functional issue. The main risk is marginally increased voltage droop on RF_VCC during SX1276 TX — acceptable to verify during bring-up rather than treat as a blocking deviation.
Action: Verify RF_VCC rail stability during TC-P-08 (RF supply rail voltage at transceiver RF pin) with SX1276 in TX mode. If droop is within acceptable range, close this notice. If significant droop is observed, source 4u7 and rework before continuing.
Status
BOD is intentionally disabled in sdkconfig.defaults (CONFIG_ESP_BROWNOUT_DET=n) for R0 development.
Reason for disabling
BOD falsely triggered during WiFi TX association despite a stable 3.3 V rail (confirmed on bench multimeter). Likely caused by inrush current on WiFi startup exceeding the ESP32-C6's internal brownout detection threshold before the bulk capacitance settles.
Production requirement
BOD must be characterised and re-enabled before production. Required actions:
- Measure actual 3V3 rail dip under WiFi TX load (oscilloscope, 100 µs resolution)
- Determine minimum voltage during worst-case load (cold WiFi association)
- Select BOD threshold below that minimum to prevent false triggers
- Re-enable
CONFIG_ESP_BROWNOUT_DET=ywith appropriate threshold
Risk
Without BOD, the device will not reset cleanly on low battery. This is acceptable for development (USB-powered) but not for battery-operated field use.
Assumption
Each Raspberry Pi's operational Wi-Fi SSID and password are derived deterministically from the unit's serial number or MAC address. This makes each Pi self-identifying, auditable, and reproducible without a central credential database.
Agreed in principle during E-025 concept discussion. Not yet approved.
Why Approval Is Needed
- Naming/credential scheme becomes a fleet-wide standard — changing it later requires re-provisioning all deployed ESP32 units.
- May intersect with site security policies (predictable credentials derived from hardware identifiers).
- Head of operations must sign off before this is implemented in firmware or Pi OS image.
Blocked Action
E-025 next step "Resolve SSID/password derivation scheme" is blocked on this approval. Prototype work can proceed with hardcoded test credentials in the interim.
Resolution Needed
Head of operations to approve or propose an alternative scheme. Once approved, promote to a decision entry and close this notice.
Charge cycle verification — A003460, 2026-06-10
Data sources: charge_profile.txt (original, session cut short) + new_charge_profile.txt (complete cycle including discharge history and termination).
Phase summary
| Phase | Uptime | Duration | vbat | ibat (ADC) |
|---|---|---|---|---|
| Discharge (pre-charge) | 00:01 → 19:46 | ~19h 44m | 3.989 → 3.066 V | 13.2 mA (offset) |
| CC | 19:46:15 → ~20:11 | ~25 min | 3.740 → 4.142 V | ~578–581 mA |
| CV | ~20:11 → 1d 00:40:11 | ~4h 29 min | 4.142 → 4.169 V | 581 → 68.4 mA |
| Termination | 1d 00:40:22 | — | 4.122 V | 13.2 mA (noise) |
| Post-charge rest | 1d 00:40 → 1d 01:12+ | 31+ min | 4.122 → 4.100 V | 13.2 mA |
Total charge time (CC start → termination): ~4h 54 min
Termination event
- Last sample with charge current: ibat = 68.4 mA at uptime 1d 00:40:11
- Next sample: ibat drops to 13.2 mA (noise floor) — BQ24075 terminated
- Net termination current (minus ~13 mA offset): ~55 mA
- Expected BQ24075 ITERM at C/10 of ~570 mA CC: ~57 mA — consistent ✓
ADC offset note
All ibat readings carry a ~13 mA offset (noise floor visible when no charge current flows). Accurate current measurement deferred to R1 (calibrated INA333 circuit). Qualitative charge algorithm shape is valid for R0 verification purposes.
Discharge runtime
Battery ran ~19h 44 min from resting charge (~3.989 V) to ~3.066 V. Logging gaps present due to network drops from logging PC; trend intact.
BQ24075 verification conclusions
- CC phase present and stable ✓
- CC→CV transition at Vreg ✓
- CV taper monotonically declining ✓
- Termination at ~C/10 ✓
- Post-termination vbat relaxes normally ✓
Test Setup
- DUT: A003460
- Start: 2026-06-11 ~09:19:30 (USB disconnected, battery fully charged)
- Mode: deep sleep, nominal 60 s wake interval
- Test paused: 2026-06-12 ~15:54 to reconnect device for firmware work
- Total heartbeats captured: ~430+
- Test status: partial — full runtime not reached; device still had significant charge remaining
Data Gap Note
Uptime jumps from 0d 08:24:02 to 0d 23:48:52 — a 15 h 24 min gap. Device ran continuously; subscriber was offline overnight (approx 2026-06-11 16:40 to 2026-06-12 08:10 real time).
RTC Drift Confirmed
Measured over the full 30.5 h dataset:
| Value | |
|---|---|
| Real elapsed | 109 960 s (30 h 32 m 40 s) |
| Uptime elapsed | 109 610 s (30 h 26 m 50 s) |
| Slow by | 350 s |
| Rate | 3 183 ppm |
Consistent with earlier estimate. See E-030 for root cause and R1 fix.
Wake Interval
Consecutive heartbeat uptime intervals: consistently 62–63 s.
- Breakdown: ~60 s deep sleep + ~3 s active (WiFi connect + publish overhead)
- In real time: ~63.2 s per cycle
Voltage Discharge Profile (clean readings, outliers filtered)
| Period | Uptime range | Start V | End V | Rate |
|---|---|---|---|---|
| Post-charge settling | 1:06 → 2:00 | 4.065 | 4.054 | 12.2 mV/h |
| Settling | 2:00 → 4:00 | 4.054 | 4.035 | 9.5 mV/h |
| Settling | 4:00 → 6:00 | 4.035 | 4.020 | 7.5 mV/h |
| Settling → plateau entry | 6:00 → 8:24 | 4.020 | 4.006 | 5.8 mV/h |
| Gap — most reliable rate | 8:24 → 23:49 | 4.008 | 3.955 | 3.44 mV/h |
| Plateau | 23:49 → 1d 07:33 | 3.955 | 3.950 | ~0.65 mV/h |
Device entered the LiPo flat plateau at ~3.95 V. Voltage was moving very slowly at test pause — battery had substantial charge remaining.
Average Current Estimate
Derived from gap segment (most reliable):
- 4.008 V → 3.955 V over 15.42 h = ~10% SoC consumed = ~50 mAh (500 mAh cell assumed)
- Average current: ~1.6 mA at 1-minute wake interval
Breakdown (estimated):
- Deep sleep: ~100–200 µA (ESP32-C6 RTC + MCP1700 quiescent + leakage)
- Active (WiFi + MQTT + overhead, ~3 s/cycle): burst ~50–80 mA averaged over 63 s cycle = ~3–4 mA contribution
- Combined: consistent with ~1.6 mA observed
ADC Glitches
Multiple spurious low-voltage spikes visible throughout (readings 30–80 mV below stable neighbours). Consistent with E-021 (missing C28 on ADS7828). Not real voltage events.
Projected Full Runtime (500 mAh battery)
- Average current: ~1.6 mA → 500 mAh / 1.6 mA ≈ 310 h ≈ 13 days
- Target established: ≥ 10 days at 1-minute wake interval (see E-032)
- Full stress test to be run at a later stage with logging coverage through to cutoff voltage
Next Steps
- Full discharge test deferred — reconnect device, work on firmware
- When stress test resumes: log continuously through 3.80 V, 3.70 V, 3.60 V to capture knee and terminal drop
- Verify average current improves with shorter active time (OTA, static IP, faster MQTT connect)
BQ24075 charger (U1): the paired BAT pad (pin 3) and OUT pad (pin 11) are left unconnected — only one pad of each pair carries the battery / system-output current. The datasheet defines BAT = pins 2,3 and OUT = pins 10,11 as paired power pads (BAT rated 4.5 A discharge / 1.5 A charge). Does the single connected pad's trace/via carry the worst-case battery + system current, or should the second pad of each pair be connected per the datasheet? Raising for the battery + system power path.
Receipts: ["observation:8", "component:U1", "datasheet:BQ24075TRGTR", "net:+BATT", "net:Net-(U2-VIN)"]
— odb board 3, concern CON-001
Beacon (ESH10000671 R0) — Probe design review COMPLETE. Analysis run 5: 23/23 checks addressed (100%), 71% with positive evidence, 29% honest abstains (silk / fiducials / derived-value notes — need the fab layers, not connectivity). Verdict: 1 gating concern, otherwise clean.
GATING FINDING — CON-001 / OBS-8: BQ24075 charger (U1) paired power pads under-connected. BAT = pins 2,3 and OUT = pins 10,11 are paired power pads the datasheet says to tie together (BAT rated 4.5 A discharge), but pin 3 (BAT) and pin 11 (OUT) are left unconnected — only pin 2 / pin 10 carry the battery / system current. Fix: connect the second BAT and OUT pads, or verify the single-pad trace/via carries worst-case current.
CLEAN (evidence-backed): I2C bus0 (ESP32 ↔ ADS7828 + PI4IOE5V6416) and bus1 (ESP32 → J3/Sentry) — continuity, pull-ups, role consistency, single 3.3V domain, no address collision (note: 10k pull-ups are comfortable at 100 kHz, marginal at 400 kHz — sanity-check against the I2C clock); SPI ESP32 ↔ SX1276 (PA_BOOST + PE4259 antenna switch); power (8 checks auto-resolved); documentation (title block + net labels); test access (TP1–5 + J3 exposes the serial buses). The 36 single-point nets were reviewed — all benign NC/unused pins except the BQ24075 pads.
ENRICHMENT: 9 active datasheets acquired. Remaining: D1/D2 (LED) and X1 (32 MHz crystal) need an MPN in the BOM to enrich (low value — unlikely to change the verdict).
PROCESS BUGS FILED in Probe (board-tooling, not Beacon defects): BUG-005 (viewer showed a stale schematic for a no-schematic board), BUG-006 (ingest doesn't auto-publish the Trace odbBoardRef link — done manually here).
— odb board 3 (comment)
Trace cross-check — reconciling CON-001 against existing project records:
(1) E-029 (full charge cycle verified on unit A003460): the BQ24075 charges correctly — ~580 mA CC, clean CV taper, termination at ~55 mA. So the single connected BAT/OUT pad IS functional at normal current; CON-001 is NOT a functional blocker. It is a worst-case-current / thermal-margin question — the BAT path is rated 4.5 A and the single pad/trace was never stress-tested near that.
(2) E-015 (BOD disabled — ESP32 brownout false-triggers on WiFi-TX inrush, despite a stable 3.3 V on a multimeter): worth checking whether the unconnected OUT pad (pin 11) is a contributor. WiFi-TX inrush is a fast current transient down the BQ24075 OUT → MCP1700 path; with only one of the two OUT pads connected, that path has higher resistance/inductance and a deeper momentary dip — a plausible contributor to the brownout that E-015's scope action (measure the 3V3 dip under WiFi-TX) would reveal. Connecting both OUT pads is cheap insurance for CON-001 and for the brownout characterisation. (Hypothesis, not a claim — the BOD trigger could equally be bulk-cap / LDO transient response.)
Subject: CON-001
— odb board 3 (comment)
Intent-grounded review pass (board 3) — re-ran the review against the Trace open-issue set, each tested vs the netlist (the FR-010 case in one board):
E-013 CONFIRMED (Probe-domain, headline): R1 (10k) pulls BQ24075 EN1 to +5V (R1.1=+5V, R1.2=EN1); R2 (10k) pulls EN2 to +5V. EN1=H + EN2=H = Standby → OUT disabled (datasheet EN truth table). Intent E-003 wants EN1 LOW. So the R0 board ships with the charger output DISABLED — exactly E-013 (A003460 fixed by removing R1). A connectivity+datasheet finding Probe should auto-produce; it outranks CON-001; the bottom-up pass missed it.
E-022 CONFIRMED: INA333 (U10) V-=GND, V+=Q1-gated 3.3V (single supply), inputs across the low-side shunt near GND (pin3=battery-, pin2=GND), high gain → A2 clamps at GND. Battery-current monitoring (REQ-035/059) inoperative — confirms the team's analog root cause.
E-023 RECONCILED: +3V3 lands on J3.3/J3.9; PowerGroundShort=0 → NO 3V3-GND short in the PCB netlist. The blocking short is off-board/assembly — a mating-cable wiring error or a 0.4mm-pitch solder bridge between the 3V3 pins (3/9) and adjacent GND pins. Schematic exonerated; verify the cable + inspect J3 solder. (Earlier 'clean boundary' was netlist-correct but intent-blind.)
E-028 NARROWED (2 of 5 hypotheses ruled out at netlist level): VCC_RF (U8.24) IS supplied — +3V3 → FB1 ferrite → +3V3RF, decoupled C17/C19 (hyp #1 not a design error); the QFN thermal pad (U8.29) IS tied to GND in the design (hyp #5 is an assembly solder issue, not layout). Live causes remain: crystal load caps (checkable via CrystalLoadCaps + the 10pF CL from E-009), the RF matching network, LORA_RESETn release (firmware). The grounded pass de-risked the bench investigation.
Net: grounding-first surfaced a real charger-disable finding (E-013) in Probe's domain, confirmed E-022, exonerated the J3 schematic (E-023), and narrowed the RF blocker (E-028) — vs the bottom-up pass which found one minor pad item.
— odb board 3 (comment)
U5 (PI4IOE5V6416ZDEX) exposed die pad — pin 25, named GND — is unconnected (single-point net unconnected-(U5-GND-Pad25)). The logic ground pin 9 IS tied to GND, so the device has a return and functions, but the package EP has no copper to GND on R0. Investigate against the PI4IOE5V6416 datasheet whether the exposed pad must be bonded to GND (thermal + ground-return integrity): if mandated, R0 omits it and R1 should add the EP→GND tie + via array; if only recommended, record the disposition. Not a spare-pin NC like P0_6/7 or P1_2–7 — it is the only GND-named pad left floating.
Receipts: ["rule:SinglePointNet — net unconnected-(U5-GND-Pad25) connects only to U5.25", "netlist:U5.9 = GND (logic ground connected)", "datasheet:PI4IOE5V6416ZDEX exposed-pad / GND bonding requirement — to verify", "trace:E-004 (PI4IOE I2C address + port allocation) does not address the exposed pad", "trace:REQ-037 (GPIO expander present on I2C) — functional, unaffected"]
— odb board 4, concern CON-001
Design Rule Status
■ No violations ■ Warning ■ Error ■ Waived
Sign-offs
| Stage | Role | Signed By | Date | Statement |
|---|---|---|---|---|
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
| approved | — | demo | 2026-06-05 | — |
Bill of Materials
| Ref | Part # | Part Name | Category | Qty | Description |
|---|---|---|---|---|---|
| C1 | EGP10000653 | Capacitor 10u | Capacitor | 1 | — |
| C10 | EGP10000651 | CAP0402 2u2F | Capacitor | 1 | — |
| C11 | EGP10000653 | Capacitor 10u | Capacitor | 1 | — |
| C12 | EGP10000653 | Capacitor 10u | Capacitor | 1 | — |
| C13 | EGP10000641 | CAP0402 100nF | Capacitor | 1 | — |
| C14 | EGP10000641 | CAP0402 100nF | Capacitor | 1 | — |
| C15 | EGP10000641 | CAP0402 100nF | Capacitor | 1 | — |
| C16 | EGP10000641 | CAP0402 100nF | Capacitor | 1 | — |
| C17 | EGP10000641 | CAP0402 100nF | Capacitor | 1 | — |
| C18 | EGP10000641 | CAP0402 100nF | Capacitor | 1 | — |
| C19 | EGP10000652 | Capacitor 4u7 | Capacitor | 1 | — |
| C2 | EGP10000653 | Capacitor 10u | Capacitor | 1 | — |
| C20 | EGP10000593 | Capacitor 10p | Capacitor | 1 | — |
| C21 | EGP10000593 | Capacitor 10p | Capacitor | 1 | — |
| C22 | EGP10000641 | CAP0402 100nF | Capacitor | 1 | — |
| C23 | EGP10000595 | Capacitor 15p | Capacitor | 1 | — |
| C24 | EGP10000595 | Capacitor 15p | Capacitor | 1 | — |
| C25 | EGP10000641 | CAP0402 100nF | Capacitor | 1 | — |
| C26 | EGP10000641 | CAP0402 100nF | Capacitor | 1 | — |
| C27 | EGP10000641 | CAP0402 100nF | Capacitor | 1 | — |
| C28 | EGP10000641 | CAP0402 100nF | Capacitor | 1 | — |
| C29 | EGP10000641 | CAP0402 100nF | Capacitor | 1 | — |
| C3 | EGP10000653 | Capacitor 10u | Capacitor | 1 | — |
| C30 | EGP10000641 | CAP0402 100nF | Capacitor | 1 | — |
| C4 | EGP10000641 | CAP0402 100nF | Capacitor | 1 | — |
| C5 | EGP10000650 | CAP0402 1uF | Capacitor | 1 | — |
| C6 | EGP10001791 | A782MS227M1VLAS020 | Capacitor | 1 | — |
| C7 | EGP10001454 | CAP0805 10uF 50V | Capacitor | 1 | — |
| C8 | EGP10000641 | CAP0402 100nF | Capacitor | 1 | — |
| C9 | EGP10000641 | CAP0402 100nF | Capacitor | 1 | — |
| D1 | EGP10001684 | APT2012G | Diode | 1 | — |
| D2 | EGP10001684 | APT2012G | Diode | 1 | — |
| FB1 | EGP10001889 | MPZ2012S102 | Inductor | 1 | — |
| J1 | EGP10001935 | S2B-PH-K-S | Connector | 1 | — |
| J2 | EGP10001938 | 632723100011 | Connector | 1 | — |
| J3 | EGP10001412 | Q2 B2B conn receptacle | Connector | 1 | — |
| J4 | EGP10001928 | Conn SMA Surface Mount | Connector | 1 | — |
| L1 | EGP10001937 | LQW15AN15NG80D | Inductor | 1 | — |
| PCB1 | EGP10001925 | PCB Accordion Beacon Module R0 | PCB | 1 | — |
| Q1 | EGP10001761 | AO3407 | Transistor | 1 | — |
| R1 | EGP10000097 | Resistor 10k | Resistor | 1 | — |
| R10 | EGP10000077 | Resistor 1k5 | Resistor | 1 | — |
| R11 | EGP10000077 | Resistor 1k5 | Resistor | 1 | — |
| R12 | EGP10000077 | Resistor 1k5 | Resistor | 1 | — |
| R13 | EGP10000077 | Resistor 1k5 | Resistor | 1 | — |
| R14 | EGP10000097 | Resistor 10k | Resistor | 1 | — |
| R15 | EGP10000097 | Resistor 10k | Resistor | 1 | — |
| R16 | EGP10000145 | Resistor 1M | Resistor | 1 | — |
| R17 | EGP10000145 | Resistor 1M | Resistor | 1 | — |
| R18 | EGP10000097 | Resistor 10k | Resistor | 1 | — |
| R19 | EGP10000097 | Resistor 10k | Resistor | 1 | — |
| R2 | EGP10000097 | Resistor 10k | Resistor | 1 | — |
| R20 | EGP10000097 | Resistor 10k | Resistor | 1 | — |
| R21 | EGP10000097 | Resistor 10k | Resistor | 1 | — |
| R22 | EGP10000097 | Resistor 10k | Resistor | 1 | — |
| R23 | EGP10000097 | Resistor 10k | Resistor | 1 | — |
| R24 | EGP10000097 | Resistor 10k | Resistor | 1 | — |
| R25 | EGP10000097 | Resistor 10k | Resistor | 1 | — |
| R26 | EGP10000097 | Resistor 10k | Resistor | 1 | — |
| R27 | EGP10000097 | Resistor 10k | Resistor | 1 | — |
| R28 | EGP10001011 | Resistor 0805 100m | Resistor | 1 | — |
| R29 | EGP10000121 | Resistor 100k | Resistor | 1 | — |
| R3 | EGP10000128 | Resistor 200k | Resistor | 1 | — |
| R30 | EGP10000097 | Resistor 10k | Resistor | 1 | — |
| R31 | EGP10000001 | Resistor 0 | Resistor | 1 | — |
| R32 | EGP10000097 | Resistor 10k | Resistor | 1 | — |
| R33 | EGP10000097 | Resistor 10k | Resistor | 1 | — |
| R34 | EGP10000097 | Resistor 10k | Resistor | 1 | — |
| R35 | EGP10000001 | Resistor 0 | Resistor | 1 | — |
| R36 | EGP10000001 | Resistor 0 | Resistor | 1 | — |
| R37 | EGP10000121 | Resistor 100k | Resistor | 1 | — |
| R38 | EGP10000097 | Resistor 10k | Resistor | 1 | — |
| R39 | EGP10000097 | Resistor 10k | Resistor | 1 | — |
| R4 | EGP10000121 | Resistor 100k | Resistor | 1 | — |
| R5 | EGP10000121 | Resistor 100k | Resistor | 1 | — |
| R6 | EGP10001147 | Resistor 49k9 | Resistor | 1 | — |
| R7 | EGP10000121 | Resistor 100k | Resistor | 1 | — |
| R8 | EGP10000121 | Resistor 100k | Resistor | 1 | — |
| R9 | EGP10000115 | Resistor 56k | Resistor | 1 | — |
| U1 | EGP10001929 | BQ24075TRGTR | IC | 1 | — |
| U10 | EGP10001934 | INA333AIDGKT | IC | 1 | — |
| U2 | EGP10001930 | MCP1700T-3302E/MB | IC | 1 | — |
| U3 | EGP10001931 | ESP32-C6-MINI-1-N4 | IC | 1 | — |
| U4 | EGP10001794 | SRV05-4LA 4A | Diode | 1 | — |
| U5 | EGP10001021 | PI4IOE5V6416ZDEX | IC | 1 | — |
| U6 | EGP10000946 | ADS7828EB/2K5 | IC | 1 | — |
| U7 | EGP10001154 | REF3425TIDBVR | IC | 1 | — |
| U8 | EGP10001932 | SX1276IMLTRT | IC | 1 | — |
| U9 | EGP10001933 | 4259-63 | IC | 1 | — |
| X1 | EGP10001939 | ECS-320-10-37B-CKY-TR3 | Crystal | 1 | — |