AIGC标识 STM32F407 + HT1621 段码 LCD 偶发白屏:为什么硬件复位无效,断电却能恢复?

事先叠甲,问题是我遇到的真实问题,bug又比较重要,进而由AI代笔写的文章

前言

项目使用 STM32F407 驱动 HT1621(32×4 RAM 映射 LCD 驱动器)和一块定制段码 LCD。设备长期运行后偶尔会出现近乎完全白屏,只残留少量不完整段码;此时 STM32 仍在正常采集、联网和输出日志,按硬件复位键也无法恢复,只有整机断电后重新上电才可能恢复。

本文记录一次从“怀疑应用刷新”到“确认外部 LCD 控制器状态异常”的完整排查过程,以及最终采用的渐进式修复方案。

图片来源说明:第一张图是在另一台设备上复现的同类故障,仅用于展示故障现象;第二张图才是本次目标设备修复后的实际画面。两张图不是同一台设备的严格前后对比。

测试环境:

  • 主控:STM32F407VET6;
  • LCD 控制器:HT1621 兼容控制器,4COM、32SEG;
  • 操作系统:FreeRTOS;
  • 调试器:J-Link,SWD 接口;
  • 运行日志:COM7,460800 baud。

故障现象

ht1621-white-screen-other-device

图 1:另一台设备复现的同类故障。屏幕接近完全空白,仅残留几个不完整段码。

故障具有以下特征:

  • LCD 正常工作一段时间后突然白屏,偶尔短暂出现部分段码。
  • STM32 主程序没有死机,温湿度采样、RTC、MQTT、CDC 心跳仍在运行。
  • 只复位 STM32 无法恢复。
  • 完全断电再上电可以恢复,但运行一段时间后可能再次出现。
  • 较早版本的设备也出现过类似现象,因此不能简单归因于后来增加的 ESP32-C3 RTS/CTS 信号。

系统结构

LCD 控制链路如下:

显示刷新任务 ─┐
              ├─> CHIP1621 驱动 ─> CS / WR / RD / DATA ─> HT1621 ─> COM/SEG ─> 段码屏
蜂鸣器任务   ─┘

HT1621 不在 STM32 芯片内部,它拥有独立的系统振荡器、LCD 偏压发生器、串行接口状态和显示 RAM。STM32 的 NRST 只复位 MCU;如果 HT1621 的 VDD 没有同时断开,它的内部状态不会得到真正的掉电复位。

这正好解释了一个关键现象:为什么按硬件复位无效,而断电重新上电有效。

先确认:白屏时 MCU 是否仍在运行

故障期间通过 COM7、460800 baud 观察日志,显示刷新和系统心跳仍然存在:

[CDC_DIAG]: [CDC_TASK] Heartbeat | tick=20161 | mode=0 |
q_waiting=0/512 | paused=0 | cmd_idx=0

[DisplayDataUpdateTask]: RTC 时间: 2026/08/04 13:45:05

因此首先排除了以下方向:

  • STM32 整机卡死;
  • FreeRTOS 调度完全停止;
  • 显示任务没有被周期唤醒;
  • 固件整体运行失败。

问题范围被缩小到 STM32 与 HT1621 之间的总线、HT1621 内部状态、LCD 偏压/时钟以及物理连接。

第一轮修复:消除共享总线竞争

显示刷新和蜂鸣器音调命令共享同一组 HT1621 GPIO。原实现没有互斥保护,两项任务如果同时操作 CS、WR 和 DATA,可能把两个合法事务交错成一个非法帧。

第一轮修改包括:

  1. 为所有 RAM 写入、RAM 读取、初始化和蜂鸣器命令增加同一把静态互斥锁;
  2. MCU 启动时把 CS、WR、RD 设置为高电平安全空闲状态;
  3. 每次初始化前先拉高 CS,重新同步 HT1621 串行接口;
  4. 保证任何失败路径都会释放总线锁。

核心结构如下:

th_result_t Chip1621WriteRam(uint8_t start_address,
                             const uint8_t *data,
                             size_t length)
{
    /* 参数校验和完整帧构建省略,bits/written 已在加锁前生成。 */
    th_result_t result = chip1621_board_bus_lock();
    if (result != TH_RESULT_OK) {
        return result;
    }

    CS_SET(CHIP1621_ENABLE);
    Chip1621Driver_SendBits(bits, written);
    CS_SET(CHIP1621_DISABLE);

    return Chip1621Driver_UnlockBus(TH_RESULT_OK);
}

但烧录后,已经处于白屏状态的控制器仍未恢复。这个结果并不代表互斥锁无效,而是说明:防止产生新错误,与恢复已经卡住的外部控制器,是两个不同问题。

第二轮排查:逐层排除应用和 RAM 写帧

为了避免凭感觉修改,依次进行了以下真机隔离测试:

诊断步骤 结果 排除内容
禁用写后 RAM 回读 无改善 白屏并非单次回读校验失败造成
停止业务刷新与蜂鸣器,仅写一次 128 个 1 只显示“状态”相关残留段 应用层显存内容不是主因
把 16 字节连续写改成每个 RAM 地址独立写 仍只有相同残留段 地址自动递增和长连续帧不是主因
执行完整控制器恢复序列后再次全段写入 全部段码点亮 LCD 玻璃、COM/SEG、GPIO 和 RAM 写入链路正常

其中最关键的是最后一步:没有更换屏幕、排线或控制器,只改变初始化序列,128 个段码就全部能够点亮。这直接证明硬件链路具备正常显示能力,故障核心位于 HT1621 的内部运行状态。

真正有效的恢复序列

旧初始化只在一个连续命令帧中发送:

SYS EN → BIAS → LCD ON

这足以启动处于正常复位状态的 HT1621,却不足以覆盖错误时钟源、测试模式、LCD 偏压状态或命令失步等异常情况。

最终采用的恢复序列是:

SYS DIS → LCD OFF → RC 256K → NORMAL → BIAS 1/3 + 4COM → SYS EN → LCD ON

并且每条命令都使用独立 CS 帧。CS 回到高电平后,HT1621 会结束当前事务并初始化串行接口;即使某一帧此前发生错位,也不会继续污染后面的命令。

命令定义:

#define CHIP1621_SYS_DIS       0x00
#define CHIP1621_SYS_EN        0x01
#define CHIP1621_DISPLAY_OFF   0x02
#define CHIP1621_Display_ON    0x03
#define CHIP1621_RC_256K       0x18
#define CHIP1621_BIAS          0x29
#define CHIP1621_NORMAL_MODE   0xE3

独立命令事务:

static void Chip1621Driver_SendCommandTransaction(uint8_t command)
{
    CS_SET(CHIP1621_ENABLE);
    Chip1621Driver_SendCommandMode();
    Chip1621Driver_SendCommand(command);
    CS_SET(CHIP1621_DISABLE);
    Chip1621Driver_DelayWriteHigh();
}

最终初始化:

Chip1621Driver_SendCommandTransaction(CHIP1621_SYS_DIS);
Chip1621Driver_SendCommandTransaction(CHIP1621_DISPLAY_OFF);
Chip1621Driver_SendCommandTransaction(CHIP1621_RC_256K);
Chip1621Driver_SendCommandTransaction(CHIP1621_NORMAL_MODE);
Chip1621Driver_SendCommandTransaction(CHIP1621_BIAS);
Chip1621Driver_SendCommandTransaction(CHIP1621_SYS_EN);
Chip1621Driver_SendCommandTransaction(CHIP1621_Display_ON);

为什么还要暂时禁用 RAM 回读

项目曾增加写后回读校验。读取 HT1621 RAM 时,需要把 DATA 从输出切换为输入,并驱动 RD 时钟;读取完成后再恢复 DATA 输出方向。

这套逻辑在主机桩测试中可以验证位序,但真实硬件尚未通过逻辑分析仪确认方向切换、总线释放和采样窗口。它又与显示写入、蜂鸣器命令共用同一组线路,因此最终固件暂时不绑定 RAM 回读回调,只保留经过真机验证的写入路径。

这不是宣称“回读一定是唯一根因”,而是在证据不足时移除一个没有必要进入生产路径的风险点。

官方数据手册给出的重要提示

Holtek 的 HT1621 数据手册给出了两个与本次现象高度一致的信息:

  1. 如果上下电时序不满足要求,内部 POR 可能无法正常工作;
  2. 当 VDD 曾低于工作电压时,应降到 0V 并保持至少 20ms,之后再重新上升;同时建议主控在上电后主动初始化 HT1621。

此外,CS 高电平主要负责终止通信并初始化串行接口,并不等价于切断 HT1621 电源。

官方资料:Holtek HT1621/HT1621G 数据手册

因此,“MCU 硬复位无效、整机断电有效”不是随机现象,而是外部控制器未随 MCU 一起掉电复位的直接结果。

已证实的故障机制与可能的触发因素

需要区分“故障机制”和“进入故障状态的最初触发因素”。

已经通过真机实验确认的是:

  • 白屏时 STM32 主程序仍正常运行;
  • 普通 RAM 连续写和逐地址写都无法让已经异常的控制器恢复;
  • 完整恢复序列可以在不更换硬件、不整机断电的情况下重新点亮全部段码;
  • 恢复后正常显存可以持续刷新到屏幕。

尚未通过长时间逻辑分析仪抓取唯一确认的触发因素包括:

  • 显示任务和蜂鸣器任务曾经发生总线事务交错;
  • RAM 回读时 DATA/RD 方向切换使接口进入异常状态;
  • 电源瞬态下降没有满足 HT1621 的完整 POR 条件;
  • 上述因素共同作用。

因此最终修复同时覆盖“预防”和“恢复”:用互斥锁防止帧交错,用安全空闲电平和独立 CS 帧保证同步,禁用未验证回读,并在每次启动时显式重建 HT1621 的时钟、模式、偏压和显示状态。

构建、烧录与运行日志

主机测试和 STM32 固件构建通过,最终资源占用如下:

Memory region         Used Size  Region Size  %age Used
CCMRAM                   65160 B        64 KB     99.43%
RAM                     130712 B       128 KB     99.73%
FLASH                   443892 B     458240 B     96.87%

[100%] Built target F407_TH02_V3.elf

J-Link 烧录并回读校验成功:

Device "STM32F407VE" selected.
VTref=3.236V
Loading binary file lcd_recovery_normal.fwpk.bin
Reading 444404 bytes data from target memory @ 0x08010000.
Verify successful.

恢复正常版本后,COM7 日志显示显示任务继续按 5 秒周期刷新:

[DisplayDataUpdateTask]: RTC 时间: 2026/08/04 14:25:43
[DisplayDataUpdateTask]: RTC 时间: 2026/08/04 14:25:48

修复结果

ht1621-fixed-target-device
图 2:本次目标设备修复后的实际画面。时间、温度、湿度、信号和电池段码均恢复正常。

对应 Git 提交:

2fa0a390 修复CHIP1621总线竞争与复位白屏
33740aa0 修复CHIP1621异常状态恢复失败

总结

这次问题最容易误判的地方,是把“LCD 白屏”直接等同于“MCU 没有刷新”或“屏幕硬件损坏”。实际情况是 MCU 一直在正常运行,真正失效的是独立供电的 LCD 控制器状态。

排查这类问题时,可以按下面的顺序缩小范围:

  1. 先用独立日志证明主控和显示任务是否仍在运行;
  2. 固定显存并停止其他总线使用者,排除应用层覆盖;
  3. 分别验证连续写和逐地址写,排除地址自动递增;
  4. 使用全段常亮验证 RAM、COM/SEG 和 LCD 玻璃;
  5. 检查 MCU 复位是否真的覆盖了外部芯片;
  6. 按数据手册显式恢复振荡器、工作模式、偏压和显示开关;
  7. 对共享 GPIO 总线增加事务级互斥,不让多个任务各写一半帧。

最重要的经验是:外部芯片仍有电时,复位 MCU 不等于复位整个系统。 对没有独立 RESET 引脚的器件,必须预留一套能够从未知内部状态恢复的完整初始化序列。


建议标签:STM32HT1621FreeRTOS嵌入式LCDJ-Link故障排查

posted @ 2026-08-04 15:40  .Peter  阅读(5)  评论(0)    收藏  举报