14、RDA8910(4GCAT1)CSDK二次开发:CSDK程序死机了怎么办?

目录

点击这里查看所有博文

  本系列博客所述资料均来自合宙官方,并不是本人原创(只有博客是自己写的),csdk只是得到了口头的允许公开授权。出于热心,本人将自己的所学笔记整理并推出相对应的使用教程,方面其他人学习。为国内的物联网事业发展尽自己的一份绵薄之力,没有为自己谋取私利的想法。若出现侵权现象,请告知本人,本人会立即停止更新,并删除相应的文章和代码。

  本系列博客基于紫光展锐的RDA8910 LTE Cat 1 bis芯片平台开发。理论上适用于合宙的Air720U、Air724U、广和通L610以及安信可的cat-01模块。

  各个厂家的部分配置文件可能不一样,也许会导致设备出现奇怪的问题,其他的模块我也不确定能不能用,自行测试。但是有一点编译下载和监视流程基本一样,可供参考。

  先不管支不支持,如果你用的模块是是紫光展锐的RDA8910,那都不妨一试,也许会有意外收获(也有可能变砖,慎重!!!)。

  我使用的是Air724UG开发板,如果在其他模块上不能用,那也不要强怼,也许是开发包不兼容吧。这里的代码是没有问题的。例程仅供参考!

一、前言

  前几天米总直播iic遇到了死机的问题。哎,怎么找都找不到死在哪里。俗话说的好,解决bug的办法就是删除bug,于是乎米总就开始了删代码找bug之旅。
在这里插入图片描述

  直播结束后,我也想到了之前我用csdk写代码的时候。那时遇到了错误,手上又没有什么有效的调试手段。只能采用printf调试大法,每一行执行结束都往串口打印一个数字,这样就能看到程序死机死在了哪里,变量信息也可以使用这个办法打印出来看。这仅限于代码量少的情况,可以尝试使用这个办法调试找bug。如果代码量多,这个办法根本就行不通。

  那么今天,当你看到这篇文章的时候。这个问题又将不复存在。

在这里插入图片描述

  你猜的没错,我又带着解决办法来了,让你有办法能够轻松找到程序在什么地方发生了宕机。让你能够轻松的看到程序中的全局变量和局部变量的信息。让你找bug时不再是那么的费力!

二、编写程序

/***************
	demo_hello_Debug
****************/

#include "iot_debug.h"
#include "iot_os.h"

HANDLE demo_hello_Debug_task;
int demo_hello_Debug_num = 0;
static void demo_hello_Debug(PVOID pParameter)
{
    iot_debug_print("[hello]demo_hello_Debug");
    //关闭看门狗,死机不会重启。默认打开
    iot_debug_set_fault_mode(OPENAT_FAULT_HANG);
    //打开调试信息,默认关闭
    iot_vat_send_cmd("AT^TRACECTRL=0,1,3\r\n", sizeof("AT^TRACECTRL=0,1,3\r\n"));

    volatile int n = 0;
    for (n = 0; n < 15; n++)
    {
        demo_hello_Debug_num++;
        iot_debug_print("[debug]hello world %d", n);
        iot_os_sleep(1000);
    }
    n++;
    OPENAT_assert(0, __func__, __LINE__);
    iot_os_delete_task(demo_hello_Debug_task);
}

int appimg_enter(void *param)
{
    iot_debug_print("[hello]appimg_enter");

    demo_hello_Debug_task = iot_os_create_task(demo_hello_Debug, NULL, 1024, 1, OPENAT_OS_CREATE_DEFAULT, "hello_Debug");
    return 0;
}

void appimg_exit(void)
{
    iot_debug_print("[hello]appimg_exit");
}

  看到这段代码时,是不是感觉有点眼熟。没想到它又是helloworld,上篇博客也是,这篇博客还是。我就和helloworld杠上了!
在这里插入图片描述
  上面的代码中用到了三个陌生的函数,它们分别是:

  724内部自带软件看门狗,默认处于开启状态。只要程序运行异常,就会自动重启。重启后异常信息就会丢失,那就没办法读取异常的堆栈信息了,所以在调试阶段推荐使用下面的命令关闭软件看门狗

/**设置软件异常时,设备模式
*@param	  mode:   OPENAT_FAULT_RESET 重启模式
				  OPENAT_FAULT_HANG  调试模式
**/
  • VOID iot_debug_set_fault_mode(E_OPENAT_FAULT_MODE mode)

  724默认关闭调试信息输出。一般情况下,设备运行后可以在通过串口调试助手发送AT命令AT^TRACECTRL=0,1,3来开启调试信息,每次下载后都需要重新开启。很麻烦,所以程序调试阶段推荐使用虚拟AT通道通过软件自动发送AT命令,达到自动打开调试信息输出的功能。

/**用来发送AT命令
*@param		cmdStr:  AT命令字符串
*@param   	cmdLen:  AT命令长度
*@return	TRUE: 成功   FALSE: 失败
*@note      注意,AT命令字符串cmdStr中需要包含"\r\n"或者"\r"结尾
**/
  • BOOL iot_vat_send_cmd(UINT8* cmdStr, UINT16 cmdLen);

  这一句代码就是搞事情的,它唯一的就是能让你的程序死机。本例程就是利用它创造了一个死机现场,用于演示。

/**assert断言
*@param		condition:	断言条件
*@param		func:	    断言函数
*@param		line:	    断言位置
*@return	TURE: 	    成功
*           FALSE:      失败
**/
  • VOID iot_debug_assert( BOOL condition, CHAR *func,UINT32 line)

  然后程序中还分别使用了一个全局变量和一个局部变量,等会死机时可以查看死机时的变量值,看看是不是符合预期。

三、下载验证

  运行一切正常,没有问题。
在这里插入图片描述
在这里插入图片描述

  等等,好像觉得有什么不对,怎么打印个helloworld就没了。以前的教程到了下载验证确实就没了,但是今天才刚刚开始。
在这里插入图片描述

  只要等到了上面这样两个东西,那我们今天的内容就正式开始!(没有等到继续等,大概也就15s时间)。

四、启动调试

4.1、GDB读取堆栈信息

4.1.1、点击Tools标签下面的GDB Launcher

在这里插入图片描述

4.1.2、在打开的小窗中选择相应的文件。

在这里插入图片描述
  ELF框内选择工程目录下~\iot_sdk_4g_8910Main\hex\Air720U_CSDK_demo_Debug_map\CSDK_RDA8910.elf文件不要选错了!!!

在这里插入图片描述
  Mode框内选择8910 AP选项。然后点击Launch。
在这里插入图片描述

4.1.3、加载app的elf文件

  正常情况你会看到这么一个界面。
在这里插入图片描述
  下面这几个按钮等会会用到先介绍一下。从左到右分别为:【寄存器信息】,【内
存信息】,【调用栈】,【查看全局变量】,【局部变量】,【不知道是什么】,【gdb控制台】。
在这里插入图片描述
  点击一下第三个按钮看看效果。看到一个OPENAT_assert,而它的上面就只有几个问号。我们的程序中调用的是iot_debug_assert,它们都有一个关键字那就是assert。实际上iot_debug_assert调用的就是底层提供的OPENAT_assert接口。那为什么调试工具能找到OPENAT_assert而找不到iot_debug_assert呢。
在这里插入图片描述
  上面的现象就是因为刚才加载的实际上是底层的elf文件,现在还没有加载用户编译的app.elf文件。想要加载用户的elf文件,只需要点击一下最后一个按钮(gdb控制台),然后在打开的窗口中输入下面这段命令source D:\AirJob\RDA8910CSDK\iot_sdk_4g_8910Main\start.gdb。这个命令不是固定的,需要根据你工程存放的实际位置修改。
在这里插入图片描述
注意:输入之前先检查一下工程的根目录下是不是生成了一个start.gdb文件。这个文件是编译结束后自动生成的,需要在gdb控制台里面执行一下。
在这里插入图片描述

  输入结束后控制台会答应一段乱七八糟的数据,只要找一下里面有没有demo_Debug.c这个字段,如果找到了那就成功一半了。
在这里插入图片描述
  加载成功之后再次点击第三个按钮(需要将之前打开的Stack窗口关闭,重新打开)。这时发现之前的??被换成了函数。中间的一个demo_hello_Debug就是我们刚才编写的测试任务,在左边也看到了死机位置。
在这里插入图片描述

4.2、查看变量信息

  在demo中我们写了一个demo_hello_Debug_num的全局变量还有一个局部变量用来测试。这里看看能不能在死机时把变量的信息读取出来。

4.2.1、通过内存信息读取(这个方法只适用于全局变量!!!


  打开~\iot_sdk_4g_8910Main\hex\Air720U_CSDK_demo_Debug_map\app.map文件,搜索demo_hello_Debug_num记住它前面的地址0x80f00620在这里插入图片描述
  点击第三个按钮,输入地址信息,读取0x80f00620为首的四个字节0x0000000f
在这里插入图片描述
  分析一下程序,全局变量int类型为4个字节。从0开始,在for循环内自加15次。退出循环,然后死机,那么demo_hello_Debug_num的结果为15,而15等于十六进制的0x0f。又因为int是四个字节,所以15应该等于0x0000000f,看一下是不是和上面读取到的数据一样。

int demo_hello_Debug_num = 0;
.....
{
.....
    for (n = 0; n < 15; n++)
    {
        demo_hello_Debug_num++;
        iot_debug_print("[debug]hello world %d", n);
        iot_os_sleep(1000);
    }
    n++;
    iot_debug_assert(0, __func__, __LINE__);
.....
}

4.2.2、通过Watch读取(局部变量也可以)

  有人讲,哎呦这好麻烦啊。还要看map里面的地址,自己去内存找。那么简单的方法来了。
在这里插入图片描述
  如上图所示,点击第4个按钮,在输入框分别输入demo_hello_Debug_numn,最后窗口就会显示出变量的信息。
注意:这里只能查看没有被编译器优化的局部变量值。如果被优化了那就看不了!定义变量时加上volatile关键词可防止被优化。
在这里插入图片描述

4.2.3、简单残暴直接看

  鼠标悬停在对应的变量上面稍等片刻,变量值就出来了 ̑̑ฅ( ˃̶˙ω˙˂̶ ฅ) ​​​
在这里插入图片描述
在这里插入图片描述

不会下载的点击这里,进去查看我的RDA8910 CSDK二次开发入门教程专题第一篇博文1、RDA8910CSDK二次开发:环境搭建里面讲了怎么下载
这里只是我的学习笔记,拿出来给大家分享,欢迎大家批评指正,本篇教程到此结束

©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页