Files
meshtastic_firmware/variants/nrf52840/diy/moonshine_NRF52/DIAGNOSTICS.md
T
kevin e7c82d0b69 修复发射重启:RXEN冲突+POFCON关闭
- 移除variant_nrf52LoopHook中P0.11调试翻转代码(根因:TX时
  DIO2拉高TXEN,loop hook同时翻转RXEN导致双高,射频开关
  未定义行为->PA电流尖峰->VDD跌落->HardFault)
- 定义SX126X_RXEN(P0.11),由RadioLib在TX时拉低/RX时拉高,
  与DIO2驱动的TXEN协调配合
- POFCON关闭逻辑从只执行3次改为每次loop检查,防止SoftDevice
  重新开启
- 修正initVariant注释(SystemInit已处理PSELRESET,此为兜底)
- 添加DIAGNOSTICS.md记录SWD诊断过程和硬件修复建议
2026-07-20 14:13:16 +08:00

6.4 KiB
Raw Blame History

Moonshine NRF52 - TX 重启问题诊断报告

症状

发送消息时设备立即重启。首次修复(RXEN 冲突 + POFCON 关闭)后问题依然存在。

诊断方法

通过 CMSIS-DAP SWD 探针 + OpenOCD 读取 nRF52840 内部寄存器和异常栈帧:

  1. 读取 RESETREASGPREGRETPOFCONEVENTS_POFWARN 确定复位类型
  2. HardFault_Handler / __assert_func / lfs_assert / abort 设置硬件断点
  3. 崩溃命中后通过 DCRSR/DCRDR 读取 PSP/MSP,从栈帧提取 faulting PC/LR

诊断结果

第一轮:复位原因分析

寄存器 含义
_reset_reason (Adafruit 缓存) 0x00000004 软件复位 (NVIC_SystemReset)
EVENTS_POFWARN 0 未触发电源故障警告
GPREGRET 0x00 非 lfs_assert(否则为 0xF5
error_code 0 无关键错误记录
POFCON 0x0003 仍然开启(SoftDevice 覆盖了关闭操作)

结论:软件触发的复位,排除了 POFCON/BOD/POR。最可能来源是 __assert_func()HardFault_Handler

第二轮:HardFault 捕获

发现 nRF52 + FreeRTOS 构建中,src/platform/nrf52/hardfault.cpp 的诊断版 HardFault_Handler 被 LTO 优化掉,实际使用的是 Adafruit core 的简化版(debug.cpp:60,直接 NVIC_SystemReset() 丢弃所有故障上下文)。

variant.cpp 中添加诊断版 HardFault_Handlervariant 代码排除在 LTO 之外),重新捕获。

第三轮:异常栈帧分析

断点命中 HardFault_Handler 后,通过 DCRSR 读取 PSP,从 PSP 指向的异常栈帧提取寄存器:

寄存器 含义
PC 0x0007d464 SEGGER_RTT_vprintf(故障指令)
LR 0x0007d3f5 SEGGER_RTT_vprintf(调用者)
PSP 0x2001e2f0 有效 RAM 地址
PSR 0x01000000 有效(Thread mode, Thumb
CFSR 0x00008200 UNSTKERR + BFARVALID
HFSR 0x40000000 FORCED(可配置故障升级为 HardFault)
BFAR 0x5c28f5c3 每次不同的无效地址

CFSR 解码:

  • UNSTKERR (bit 11 of BFSR) - 异常返回(unstacking)时总线错误
  • BFARVALID (bit 15 of BFSR) - BFAR 包含有效故障地址

多次捕获的 BFAR 值:

  • 0x851eb852
  • 0x2b020c4a
  • 0x374bc6a8
  • 0x5c28f5c3

根因分析

BFAR 每次不同 -> 不是确定性代码 bug,是随机因素。

完整故障链:

  1. TX 触发 -> E22-400M33S PA 瞬态大电流 -> VDD 跌落
  2. TX 路径中的日志函数(SEGGER_RTT_vprintf)正在执行
  3. 某个中断发生(BLE/SoftDevice 中断)
  4. 中断返回时,VDD 跌落导致 RAM 读取不稳定
  5. unstacking 从 PSP 读取栈帧时某个字返回无效值 -> UNSTKERR(总线故障)
  6. 总线故障升级为 HardFaultFORCED
  7. HardFault_Handler -> NVIC_SystemReset() -> 设备重启

关键证据:

  • BFAR 每次不同 -> 随机因素(VDD 跌落导致 RAM 读取错误),非确定性代码 bug
  • PSP 帧有效(PC/LR/PSR 都正常)-> 栈本身没损坏,是 unstacking 过程中的瞬态错误
  • POFWARN=0 -> 不是 POFCON 触发的
  • DCDC 未启用DCDCEN=0-> 使用低效 LDOVDD 跌落更严重
  • POFCON 仍开启(0x0003-> SoftDevice 覆盖了 sd_power_pof_enable(0) 调用

这是硬件电源设计问题,软件只能缓解。

硬件修复建议

1. 增加去耦电容(最有效)

在 E22-400M33S 模块的 VCC 引脚附近增加:

  • 100µF 电解电容(提供瞬态电流储备)
  • 0.1µF 陶瓷电容(高频去耦,紧贴 VCC 引脚)
  • 可选:10µF 钽电容(低 ESR,响应快)

2. 检查电源供电能力

  • 电池/LDO 的瞬态电流规格需满足 PA 峰值电流(E22-400M33S 在 2dBm 输出时约 500mA 峰值)
  • 检查电池内阻,老化和低温会显著增加内阻导致 VDD 跌落

3. 启用 nRF52 DCDC

RF-BM-ND05 模块如果焊有 DCDC 电感(查看模块丝印或数据手册的 DCDC 引脚),可通过软件启用:

// 在 initVariant() 或 nrf52Setup() 中
sd_power_dcdc_mode_set(NRF_POWER_DCDC_ENABLE);

DCDC 效率(~90%)远高于 LDO(~50%),能显著降低 VDD 跌落幅度。需确认硬件上有 DCDC 电感连接(DEC4 到 DCC 引脚之间有 10µH 电感),否则不能启用。

4. 降低 TX 功率(软件缓解,已实施)

variant.hSX126X_MAX_POWER=22dBm),PA 增益 25dB -> 约 27dBm 输出。如仍重启可进一步降低到 0 或 -9。

当前软件状态

变体已应用以下软件修复:

  1. SX126X_RXEN 定义variant.h- P0.11 由 RadioLib 控制,TX 时拉低、RX 时拉高,与 DIO2 驱动的 TXEN 协调
  2. POFCON 持续关闭variant.cpp variant_nrf52LoopHook)- 每次 loop 检查并关闭被 SoftDevice 重新开启的 POFCON
  3. 移除了 P0.11 调试翻转代码(原 variant_nrf52LoopHook 中的 debug toggle
  4. 移除了 HardFault 诊断代码variant.cpp- 恢复为 Adafruit core 的默认 HardFault_Handler
  5. 移除了 -Wl,-z,muldefsplatformio.ini)- 诊断时用于允许多重定义的链接器选项

软件层面已无法进一步缓解,需要硬件改动(去耦电容 / DCDC 电感)来解决 PA 瞬态电流导致的 VDD 跌落。

复现与验证方法

构建

pio run -e moonshine_NRF52_node

烧录(CMSIS-DAP via OpenOCD

openocd -f interface/cmsis-dap.cfg -f target/nrf52.cfg \
  -c "init; program .pio/build/moonshine_NRF52_node/firmware-moonshine_NRF52_node-*.hex verify; reset run; exit"

SWD 诊断(如需重新捕获 HardFault)

  1. 安装 OpenOCDbrew install openocd
  2. 连接 CMSIS-DAP 探针(SWDSWCLK/SWDIO/3V3/GND + nRESET
  3. 读取复位原因:
    openocd -f interface/cmsis-dap.cfg -f target/nrf52.cfg -c \
      "init; halt; puts [format 'RESETREAS=0x%08x' [lindex [read_memory 0x40000400 32 1] 0]]; resume; exit"
    
    • 0x01 = pin reset, 0x02 = watchdog, 0x04 = soft reset (NVIC_SystemReset), 0x08 = CPU lockup, 0x10000 = System OFF wake
  4. 读取电源状态:
    openocd -f interface/cmsis-dap.cfg -f target/nrf52.cfg -c \
      "init; halt; puts [format 'DCDCEN=0x%08x POFCON=0x%08x REGOUT0=0x%08x' [lindex [read_memory 0x40000578 32 1] 0] [lindex [read_memory 0x40000554 32 1] 0] [lindex [read_memory 0x10000304 32 1] 0]]; resume; exit"
    
    • DCDCEN=0 -> DCDC 未启用
    • REGOUT0 低 3 位:0=1.8V, 1=2.1V, 2=2.4V, 3=2.7V, 4=3.0V, 5=3.3V, 7=默认1.8V