记一次奇特的debug经历(二)
GaoSheng Lv4

继上个月31号的文章记一次奇特的debug经历,没想到还有后续
先简单回顾一下我们上次学到了什么:
图片2
上次是问题是串口在使能DMA后,尝试进入低功耗时,MCU会重启,查看RSSR复位标志位为LPACK。上次的问题症结在于客户在BOOT里面使用MCAL初始化了一次串口,然后在APP里面使用SDK里面又初始化了一次。后面将APP里面的串口初始化部分注释掉就能正常进入低功耗(deepsleep)。
这次的问题是,如果使能DMA的串口在进入低功耗前,有收发数据的动作,会出现不能进入低功耗的情况(deepsleep)。
不过这次的问题巨大的不同点在于,这次的问题能在demo板上面,使用例程稍微改改也能复现。如果上次还能说是客户自己应用工程的问题,但如果在demo板上面使用例程也能复现那么与MCU底层的关联性就很强了。
图片3
客户工程的主要逻辑是在进入deepsleep模式前使用串口收发一次数据,后续由rtc的中断唤醒。我后面将工程里面的RTC部分(排查这部分的影响)给拿走了,改成用GPIO唤醒更加直接。还是上次debug的思路的第一条,把复杂的问题简单化这条经验。进入deepsleep后使用GPIO中断也能复现,那么这个时候就排除了RTC的影响
起初拿到客户的工程后,我并不能理解为什么客户要使用这么绕的方式来收发数据,我直接改成了使用带阻塞的一个发送一个接收。可以完成进低功耗前的收发动作(写到这猛然发现我不知不觉中运用了上次总结的第二条debug经验:对不理解的操作需要保持怀疑,不然容易被带偏)

1
2
LINFlexD_UART_DRV_ReceiveDataBlocking(2,&buff, 1,0x8FF);
LINFlexD_UART_DRV_SendDataBlocking(2,&buff,1,0xFF);

原客户使用的收发代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    // 2. 开启UART接收, 直到接收到8个字节
LINFlexD_UART_DRV_ReceiveData(2, buff, sizeof(buff));

#if 1
// 注意: # 这里if 1 #endif包围的代码, 用于等待UART2数据.
// 外部给UART2发送数据, MCU一旦接收到数据, 就会在调用POWER_SYS_SetMode后重启
uint32_t remain_bytes = sizeof(buff);
// while (LINFlexD_UART_DRV_GetReceiveStatus(2, NULL) != STATUS_SUCCESS)
PRINTF("waiting 8 bytes from UART2...\r\n");
while (1)
{
LINFlexD_UART_DRV_GetReceiveStatus(2, &remain_bytes);
// 只收8个字节就跳出循环
if (remain_bytes < sizeof(buff) - 8) {
break;
}
}
// LINFlexD_UART_DRV_SendData(2, buff, 8);
#endif

使用GPIO唤醒前使用UART2收发数据:
图片4
使用GPIO唤醒前不使用UART2收发数据(正常进入低功耗,并可以唤醒):
图片5

在尝试了各种deinit, abort, Release的API后都无果。把问题反馈给原厂,由李工推动,Diga D工大力支持下,终于找到了root cause
图片6
UART使用了DMA并有收发数据的动作,进入低功耗前要手动置LINFlexD_LINCR1_SLEEP_MASK标志位,退出后清除。如果串口还有待接收需要调用LINFlexD_UART_DRV_AbortReceivingData 函数
结合上次的问题,又可以总结一条debug的经验了:

  • 把复杂的问题简单化,排查时要大体明白各个模块的作用,确定关联性后再做注释;
  • 对不理解的操作需要保持怀疑,不然容易被带偏
  • 不要把问题排查范围局限在已有的API里面,可以尝试在还可以试着手动调整一些你认为可疑的寄存器

水平有限,有问题请多多指教

本站由 提供部署服务