【IOT开发】DEBUG_Mark

ESP32

最近在使用ESP32开发一些无线应用,在经历重重困难能够顺DE利编译-下载工程后,尝试把STM32中的程序移植到ESP32中,但由于对FreeRTOS系统了解不够深入,所以遇到了很多导致板子一直Rebooting的bug,在此记录一下。

1. 消息队列溢出

在创建一个消息队列时需要给出队列长度,同时也需要相应的读取队列信息。如果入队过多没读完就满了,队列溢出则会导致系统重启。
所以在使用消息队列时注意消息写入与读取的对应关系。

2. 中断程序卡死 看门狗异常

在程序中使用到了一个timer中断,刚写完发现一直重启,报错的原因是看门狗溢出,也就是高优先级线程卡死太久了。后来debug发现是卡死在timer中断内了。卡死的具体原因见我之前写的一个小总结:STM32-中断卡死
在ESP32-FreeRTOS系统中封装了太多层,直接去改中断标志位寄存器的值没有开放API,不过可以随意调用一个更改中断位的函数完成。
这点后来查阅官方文档,也有相应的说明:

定时器启动后,可动态产生特定事件(如“警报事件”)。如需在事件发生时调用某些函数,请通过 gptimer_register_event_callbacks() 将函数挂载到中断服务例程 (ISR)。gptimer_event_callbacks_t::on_alarm 设置警报事件的回调函数。由于此函数在 ISR 上下文中调用,必须确保该函数不会试图阻塞(例如,确保仅从函数内调用具有 ISR 后缀的 FreeRTOS API)。函数原型在 gptimer_alarm_cb_t 中有所声明。>
例如 xQueueSendFromISR、timer_group_get_counter_value_in_isr

3. printf重入

由于之前写裸机程序习惯了,没想到有一天会因为printf卡死。
具体的场景是:中断A和B同时调用了printf,然后系统就很重启。printf不能在未返回的时候再次被调用。所以在中断中尽量不要用printf发送调试信息,应该改用ESP_LOG,日志输出。
详情见:Logging library

大致就是以下几个API:

1
2
3
4
5
ESP_LOGE -error
ESP_LOGW -wornning
ESP_LOGI -information
ESP_LOGD -debug
ESP_LOGV -verbose

4. 指针导致的内存错误

在程序中需要用到结构体指针、函数指针等稍微复杂一些的指针操作时,注意指向对象前先给对象分配内存空间,不然找不到地址就会报错重启。

5. 参数异常

某些API参数设置没有保护或异常判断,输入参数溢出可能会导致错误。例如在设置定时器alarm周期时需要根据命令内容来设置,这时需要手动检测这个周期>=0,否则会导致重启。

6. 高频率任务超时

2022-9-22
今天又遇到了重启的bug,debug后发现是timer 回调函数中ESP_LOGI导致的。这玩意儿是可以重入的,但是timer的频率太高了,只有几十us,而执行一次ESP_LOGI的耗时会超过timer回调的周期,就会卡死重启。所以在高频率任务中注意任务耗时,尽量不要调用一些高耗时的API。
如果是很少启用的情况,例如几百次timer callback才会调用一次LOGI,可以使用 任务-消息队列-事件触发的逻辑 避免回调函数的重入error。

7.

2023-3-28

1
2
3
4
timer = xTimerCreate("timer", pdMS_TO_TICKS(TIMER_PERIOD_MS), pdTRUE, NULL, timer_callback);
xTimerStart(timer, 0);
...
vTaskSuspendAll(); // 暂停所有其他任务

根据搜索结果,您可能遇到了ESP32和FreeRTOS的兼容性问题。一些用户报告说,使用vTaskSuspendAll()或者taskENTER_CRITICAL()等函数会导致看门狗定时器超时或者系统崩溃12。您可以尝试使用其他的同步机制,比如信号量或者互斥锁,来代替暂停其他任务的操作

STM32

中断退出

在最近某个项目中,遇到了串口中断卡死主程序的问题,仔细debug后发现是没有读取接收缓存区buffer的原因。

1
USART_ReceiveData(USART1);        //读取一次数据,不然会一直进中断

函数里面主要的语句:

1
(USARTx->DR & (uint16_t)0x01FF); //读取USARTx->DR

USART1->DR是串口数据收发的缓存区寄存器。
串口中断标志位自动清空的前提是软件需要先读USART_SR寄存器,然后读USART_DR寄存器来自动清除。即串口中断事件发生后,如果使能的接收中断,而中断函数里面什么都不执行的话,接收中断标志位是无法自动清空的,故而,函数会一直卡在中断函数里面。

后来在定时器中断也遇到了类似的问题。由于任务需要,定时器需要根据串口命令更改不同的定时频率,但是在更改时如果只是在timer外部关闭定时器再重新initial,则程序会卡死 测试后发现是卡死在timer中断中。
timer关闭前一定要清空中中断标志,否则会在中断中出不来,所以中断timer再重启,需要的timer的中断中执行:

1
2
3
4
5
6
7
8
TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx的中断待处理位
if(IsTimerReset)
{
TIM_Cmd(TIM3, DISABLE);
TIM3_Int_Init(IRQTimes,99);//重新启用
IsTimerReset=0;
//printf("IsTimerReset=1,and timer is reset \r\n");
}

STM32-掉电重启异常 bug

问题描述:

基本相同的硬件原理图,上一版是好的,修改了 PCB 布局和走线后,新板子遇到了上电后无法工作的问题。

很诡异的 bug,烧录完程序一切正常,但是一掉电就无法工作了。

排查过程:

1.怀疑 BOOT0 接触异常 或 Reset 电位异常 ,检查后发现 BOOT0 和 Reset 电位都是正常的。

2.使用 LED 电灯标准例程,上电发现没有效果。

3.检查晶振,发现少撸完成后晶振波形正常,复位后晶振波形不正常。尝试通过延长等待 HSE 启动成功的时间常数、直接使用内部 HSI 时钟,仍然无法掉电启动。

4.更改复位电路的充电电容。怀疑是复位电路时序不对,把 C23 换成了 10uF,仍然无法正常启动。

5.突发奇想使用前两天写的一个软件 Reset,发现软件 Reset 居然可以正常重新启动。

上位机的 reset 设置:

1
2
3
4
5
6
7
serialPort1.RtsEnable = true;
serialPort1.DtrEnable = false;
Thread.Sleep(1);
// RTS高电平,DTR低电平
serialPort1.RtsEnable = false;
serialPort1.DtrEnable = true;

默认情况下 RTS DTR 都是高电平,用示波器测得的电位也是高电平。对比了一下自动下载电路的原理图,这个软件设置其实不会更改 BOOT0 和 EN 的电位,RTS 置高,DTR 无论高低,都是: BOOT0 低,EN 高,flash 启动状态。

解决方案:

把 RTS 引脚飞线到 3V3 或者把 DTR 飞线到 GND。

上位机命令把 DTR 控制成低电平后可以重启,然后飞线物理控制也可以重启,但是 DTR 高电平输出直接接地会短路,所以尝试把 RTS 飞高电平,发现也能够顺利重启。

注意 RTS 物理控制高电平时候不能进入串口下载模式,所以得用 SW 下载或者下载完程序再飞线。

虽然问题是靠运气解决的,可以尝试从结果排查原因:

飞线前后 RTS DTR 都是高电平,EN 和 BOOT0 的电位都正常,但是无法从 flash 启动,飞线后可以正常启动,用软件控制 RTS 高电平也可以。

板子的状态就像是单片机的 RST 引脚一直是拉低的,没有跑任何程序。怀疑是某些原因导致驱动能力不够,但是软件设置 RTS 或 DTR 的电平后又可以启动。检查了自动下载电路和复位电路的走线,发现没有过孔,走线也不长。。

各个引脚电位都正常,EN DTR RTS 都是 3V3,BOOT0 为 0 。

把 RTS 引脚和 3V3 接一下,就能够启动点亮 LED,从现象判断是拉高了 EN。所以之前的现象是 EN 高了(3V3),但没完全高。所以用杜邦线短接 EN 和 3V3,按 reset 可以正常启动。

把 BOOT0 和 GND 短接,按 reset 也可以正常启动。问题在自动下载电路上。虽然电位都是正常的,但可能是三极管驱动能力不够,电流太小没能正确驱动 EN 单片机内相应的模块开关?

把自动下载电路的两个三极管拆了,发现可以上电正常启动了。从电路原理图还是看不出什么问题,上面的解释也不是很能让自己认可。

感觉总结不出原因,目前知识储备还不够,大概率还是归咎于玄学,之后如果能解答了会来补充。

参考:

https://blog.csdn.net/shx_2613/article/details/124022153

https://community.st.com/s/question/0D53W00000V2YuwSAF/stm32g0-not-works-after-reset


【IOT开发】DEBUG_Mark
http://example.com/2022/08/27/【IOT开发】DEBUG_Mark/
作者
Chery Young
发布于
2022年8月27日
许可协议