找回密码
 立即注册
查看: 300|回复: 12

STC32G12K128疑似死机问题

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:3
  • 最近打卡:2026-01-23 11:03:43
已绑定手机

1

主题

8

回帖

35

积分

新手上路

积分
35
发表于 2026-1-22 13:52:58 | 显示全部楼层 |阅读模式
STC32G12K128在项目中打开了看门狗,启用了硬件I2C从机模式,产品在用户使用反馈后,说是有一定比例的类似死机现象,比较奇怪
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:3
  • 最近打卡:2026-01-23 11:03:43
已绑定手机

1

主题

8

回帖

35

积分

新手上路

积分
35
发表于 2026-1-22 13:59:13 | 显示全部楼层
STC32G12K128在项目中通过软件打开了看门狗,启用了硬件I2C从机模式,开启了 P2.4/P2.5 硬件I2C从机中断响应,P3.2与P3.7外部输入信号下降沿中断响应,产品在用户使用过程中,出现了个别的类似死机现象,芯片用在无线充电宝中,死机时没任何反应,必须把电池拆掉重新装上才能恢复正常

点评

已转技术,请耐心等待  详情 回复 发表于 2026-1-22 14:12
回复

使用道具 举报 送花

  • 打卡等级:以坛为家III
  • 打卡总天数:645
  • 最近打卡:2026-03-23 15:27:18

33

主题

2912

回帖

6555

积分

论坛元老

积分
6555
发表于 2026-1-22 14:08:52 | 显示全部楼层
如果是陷入死循环,那会被看门狗咬死。现象不应该是死机,而是周期复位。
参考例程并不是对技术参 考手册的补充,而是对技术参 考手册的解释。
技术参 考手册不应该需要参考例程作为补充,而是解释成了参考例程的样子
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:55
  • 最近打卡:2026-03-20 11:06:35

25

主题

167

回帖

1996

积分

版主

积分
1996
发表于 2026-1-22 14:12:53 | 显示全部楼层
方*** 发表于 2026-1-22 13:59
STC32G12K128在项目中通过软件打开了看门狗,启用了硬件I2C从机模式,开启了 P2.4/P2.5 硬件I2C从机中断响 ...

已转技术,请耐心等待
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:3
  • 最近打卡:2026-01-23 11:03:43
已绑定手机

1

主题

8

回帖

35

积分

新手上路

积分
35
发表于 2026-1-22 14:39:56 | 显示全部楼层
异常状态下,中断响应都没反应,指示灯和显示屏都保持熄灭状态或者指示灯保持常亮
回复

使用道具 举报 送花

  • 打卡等级:常住居民II
  • 打卡总天数:84
  • 最近打卡:2026-03-23 16:08:41
已绑定手机

4

主题

227

回帖

832

积分

高级会员

积分
832
发表于 2026-1-22 16:24:42 | 显示全部楼层
由于没见到代码,只能提出一点点建议:
不要在中断里喂狗,最好是在主循环里喂;
主循环里让某个IO取反,便于示波器观察它是否死机;

检查是否设置了“空闲状态时停止看门狗计数”
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:3
  • 最近打卡:2026-01-23 11:03:43
已绑定手机

1

主题

8

回帖

35

积分

新手上路

积分
35
发表于 2026-1-22 17:34:17 | 显示全部楼层
lcws*** 发表于 2026-1-22 16:24
由于没见到代码,只能提出一点点建议:
不要在中断里喂狗,最好是在主循环里喂;
主循环里让某个IO取反,便 ...

空闲状态时停止看门狗计数的设置是在哪里配置的?代码里休眠前没有停止看门狗计数,
另外休眠期间采用了定时唤醒功能,0.5秒唤醒一次
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:3
  • 最近打卡:2026-01-23 11:03:43
已绑定手机

1

主题

8

回帖

35

积分

新手上路

积分
35
发表于 2026-1-22 17:38:47 | 显示全部楼层
// 准备进入休眠
  if(waitingFlag == FALSE)
  {
    // 准备进入休眠状态时:
    // 显示界面处于非电量界面则立即休眠(用于)
    if(sleepFlag == SLEEP_AT_ONCE)
    {
      // 为下次唤醒后超时休眠做准备
      sleepFlag = WILL_SLEEP;
      
      // 关闭显示屏
      oled_Off();
      
      // 如果无外设接入则关闭指示灯
      if(sinkSrcAccessFlag == 0)
      {
        setLedMode(LED_OFF_NO_WAIT, 0, 0, 0);
        
        mcuStatus = MCU_SLEEP;
      }
      
      // 按键1计时及状态变量清零
      keyStatus.keyAction      = NO_CLICK;
      keyStatus.pressTimeCntEn = FALSE;
      keyStatus.pressTimeCnt   = 0;
      keyActionFlag            = FALSE;
      
      menu.cartoonSet = FALSE;
      
      // 休眠后长按允许进入小电流设置模式
      trickle_Set_En_flag = TRUE;
      
      // 配置外部中断(满足休眠状态下充电唤醒)
      exti_Config();
      
      // 设置0.5秒定时唤醒(设置为1000,实际定时为0.5秒)
      SetWakeUpTime(1000);
      
      while(1)
      {
        // 如果当前无外设接入时则关闭定时唤醒功能并直接进入休眠节能状态
        // 避免充放电状态下,休眠状态导致LED指示灯失控
        if(sw6236d_irq_chkPin)
        {
          // 关闭定时唤醒
          WKTCH &= 0x7F;
         
          // 关闭LED指示灯
          setLedMode(LED_OFF_NO_WAIT, 0, 0, 0);
         
          #ifdef CONSOLE_DEBUG
          printf("ledStatus = 4!\r\n");
          #endif
        }
        // 有外设接入的状态下,继续采集电量数据,方便后续屏显数据的实时同步
        // 无线充模块反应比较滞后,当充电设备(比如手机)退出后,无线充模块仍然会导致协议芯片状态管脚保持低电平约1分钟左右
        else
        {
          // 已通过I2C接口获取到变量值
          if(getDataFlag)
          {
            batCapValue       = batCapValueCpy;
            chargeInOutFlag   = chargeInOutFlagCpy;
            sinkSrcAccessFlag = chargeInOutFlag;
            
            getDataFlag = FALSE;
            
            if((chargeInOutFlag == INPUT_STATUS) || (chargeInOutFlag == INPUT_OUTPUT_STATUS))
            {
              inputPwrValue  = pwrValue;
              outputPwrValue = 0;
            }
            else if(chargeInOutFlag == OUTPUT_STATUS)
            {
              inputPwrValue  = 0;
              outputPwrValue = pwrValue;
            }
            else
            {
              inputPwrValue     = 0;
              outputPwrValue    = 0;
              chargeInOutFlag   = NO_ACCESS_STATUS;
              sinkSrcAccessFlag = NO_ACCESS_STATUS;
            }
          }
         
          // 确认有外设保持接入
          if(sinkSrcAccessFlag == TRUE)
          {
            // 指示灯之前已经熄灭,则此次为外设再次接入,需要等同于中断响应效果,跳出当前预休眠循环并亮屏(用于处理无线充功能的缺陷)
            // 无线充模块的缺陷:当无线充电设备退出后,无线充模块还会继续导致协议芯片SW6201的状态脚持续拉低,造成外设仍然接入的假象,导致指示灯延迟熄灭
            if(ledStatus == FALSE)
            {
              sinkSrcAccessIntFlag = TRUE;
              
              EA = 0;
              pwrSavingCnt     = 0;
              pwrSavingTimeMax = PWR_SAVING_TIME_120S;
              pwrSavingEn      = TRUE;
              waitingFlag      = TRUE;
              sleepFlag        = SLEEP_AT_ONCE;
              EA = 1;
              
              #ifdef CONSOLE_DEBUG
              printf("ledStatus = 5!\r\n");
              #endif
            }
            
            // 如果处于放电状态且电量低于警戒值则闪灯提示
            if((chargeInOutFlag == 0) && (batCapValue <= LOW_PWR))
            {
              setLedMode(LED_BLINK_WAIT, 0, 500, 500);
            }
            else
            {
              setLedMode(LED_ON_WAIT, 0, 0, 0);
            }
          }
          // 无外设接入,但协议芯片的状态管脚仍然处于被无线充模块拉低的状态
          else
          {
            setLedMode(LED_OFF_NO_WAIT, 0, 0, 0);
            
            #ifdef CONSOLE_DEBUG
            printf("ledStatus = 6!\r\n");
            #endif
          }
        }
        
        feedDog();
        
        // 进入休眠状态
        PCON |= 0x02;
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        
        // 如果因外界因素导致唤醒则跳出当前循环(外设接入或者按键按压动作)
        if(sinkSrcAccessIntFlag || keyActionFlag)
        {
          #ifdef CONSOLE_DEBUG
          printf("Running!\r\n");
          #endif
         
          mcuStatus = MCU_NO_SLEEP;
         
          batCapValue       = batCapValueCpy;
          chargeInOutFlag   = chargeInOutFlagCpy;
          sinkSrcAccessFlag = chargeInOutFlag;
         
          if((chargeInOutFlag == INPUT_STATUS) || (chargeInOutFlag == INPUT_OUTPUT_STATUS))
          {
            inputPwrValue  = pwrValue;
            outputPwrValue = 0;
          }
          else if(chargeInOutFlag == OUTPUT_STATUS)
          {
            inputPwrValue  = 0;
            outputPwrValue = pwrValue;
          }
          else
          {
            inputPwrValue     = 0;
            outputPwrValue    = 0;
            chargeInOutFlag   = NO_ACCESS_STATUS;
            sinkSrcAccessFlag = NO_ACCESS_STATUS;
          }
         
          break;
        }
      }
    }
    // 进入休眠前卡通动画
    else
    {
      // 无外设接入则倒计时为0时切换到休眠类动画
      if(sinkSrcAccessFlag == FALSE)
      {
        EA = 0;
        pwrSavingCnt     = 0;
        pwrSavingTimeMax = PWR_SAVING_TIME_120S;
        pwrSavingEn      = TRUE;
        waitingFlag      = TRUE;
        sleepFlag        = SLEEP_AT_ONCE;
        EA = 1;
        
        if(type > MENU_CARTOON_NIGHT_MARE)
          type = MENU_CARTOON_SLEEP;
        
        menu.menuIndexLast = MEUN_NO;
        menu.menuIndex     = type;
        
        type++;
      }
      // 有外设接入时(充放电状态),倒计时时间到则直接关屏并进入预休眠状态
      else
      {
        waitingFlag = FALSE;
        sleepFlag   = SLEEP_AT_ONCE;
      }
    }
  }

点评

代码核心问题分析 从你提供的休眠逻辑代码来看,死机的关键原因集中在休眠状态下喂狗不及时、中断屏蔽时间过长、I2C 从机与休眠冲突、死循环退出条件不可靠这四点: 喂狗时机不合理:feedDog()仅在休眠指令(PCON |=  详情 回复 发表于 2026-1-22 21:52
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:3
  • 最近打卡:2026-01-23 11:03:43
已绑定手机

1

主题

8

回帖

35

积分

新手上路

积分
35
发表于 2026-1-22 17:40:12 | 显示全部楼层
问题出在休眠期间的 while 循环里,很难复现异常状态,出现异常时,看门狗/中断都失效
回复

使用道具 举报 送花

  • 打卡等级:以坛为家III
  • 打卡总天数:724
  • 最近打卡:2026-03-18 07:56:47
已绑定手机

97

主题

7244

回帖

1万

积分

超级版主

积分
13791
发表于 2026-1-22 21:52:17 | 显示全部楼层
方*** 发表于 2026-1-22 17:38
// 准备进入休眠
  if(waitingFlag == FALSE)
  {

代码核心问题分析
从你提供的休眠逻辑代码来看,死机的关键原因集中在休眠状态下喂狗不及时、中断屏蔽时间过长、I2C 从机与休眠冲突、死循环退出条件不可靠这四点:
喂狗时机不合理:feedDog()仅在休眠指令(PCON |= 0x02)前执行,MCU 进入休眠后代码暂停执行,若休眠时间接近 / 超过看门狗超时时间,会触发看门狗复位(表现为死机);
总中断屏蔽时间过长:多处直接用EA=0关闭总中断后修改多个变量,期间 I2C 从机中断、外部唤醒中断无法响应,同时若喂狗操作被屏蔽,会导致喂狗超时;
I2C 从机未适配休眠状态:进入休眠前未对硬件 I2C 从机做暂停 / 状态保存处理,I2C 总线异常会导致 MCU 无法正常休眠 / 唤醒;
死循环退出条件不可靠:while(1)循环的退出完全依赖sinkSrcAccessIntFlag/keyActionFlag,若这些标志因中断被屏蔽无法置位,循环会无限执行,且分支内逻辑复杂,单次循环执行时间可能超过看门狗超时时间。
关键修改点解释
原子化喂狗:重写feedDog(),仅在喂狗瞬间关闭总中断,喂完立即开启,避免喂狗被 I2C 中断打断导致喂狗失败;同时在while(1)循环开头和休眠唤醒后各加一次喂狗,确保喂狗频率远高于看门狗超时时间。
缩短中断屏蔽时间:原代码中EA=0后修改多个变量、执行复杂逻辑,现在仅在修改关键全局变量时短暂关闭中断,其余时间保持中断开启,确保 I2C 从机中断、外部唤醒中断能正常响应。
I2C 从机适配休眠:新增I2C_Slave_Suspend()/I2C_Slave_Resume(),休眠前暂停 I2C 模块和中断,避免 I2C 总线异常导致 MCU 无法休眠;唤醒后恢复 I2C,保证通信正常。
优化循环执行效率:将喂狗操作移到while(1)循环开头,避免分支逻辑过长导致喂狗延迟;休眠唤醒后立即喂狗,防止唤醒后代码执行前看门狗超时。
额外排查建议
检查看门狗超时时间配置:建议设置为 500ms 以上,且喂狗频率控制在 100ms 以内(远小于超时时间);
休眠前关闭不必要的外设:除了 I2C,还可关闭串口、定时器等非必要外设,减少休眠时的总线干扰;
增加看门狗复位原因记录:在 MCU 启动时检测看门狗复位标志(STC32 的WDT_CONTR寄存器 bit6),通过串口打印复位原因,确认死机是否由看门狗超时导致。
总结
核心死机原因:休眠逻辑中中断屏蔽时间过长、喂狗时机不合理、I2C 从机与休眠状态冲突,导致看门狗超时复位或 MCU 无法唤醒。
关键修复:原子化喂狗保证喂狗成功率、缩短中断屏蔽时间保证 I2C / 外部中断响应、休眠前后适配 I2C 从机状态。
优化原则:休眠状态下尽量简化逻辑,减少循环内的复杂分支,确保喂狗频率远高于看门狗超时时间。

回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-3-23 18:21 , Processed in 0.115512 second(s), 92 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表