• 欢迎大家分享资料!前往留言板评论即可!

Air系列模块重启原因分析及应对策略(二)

合宙 模组资料网 4年前 (2021-05-15) 320次浏览 0个评论 扫描二维码

书接上文,本文说一下“”字诀。首先让我们回顾一下poweron reason表:

POWERON 事件 POWERON 代码 解释
rtos. POWERON_KEY 0 按键开机
rtos. POWERON_CHARGER 1 充电开机
rtos. POWERON_ALARM 2 闹钟开机
rtos. POWERON_RESTART 3 软件重启开机
rtos. POWERON_EXCEPTION 6 异常开机
rtos. POWERON_HOST 7 HOST工具控制重启开机
rtos. POWERON_WATCHDOG 8 其他原因

 

如果说“”字诀关注的是poweron reason 0,那么“闻”字诀需要重点关注的是poweron reason 368

poweron reason3时,通常有两种情况:代码主动执行rtos.restart()或者sys.restart()实现软重启;代码运行出错(语法错误,内存不足、AT执行超时等多种可能性),底层自动重启;

poweron reason6时,只有这一种情况:底层出错,请上报bug

poweron reason8时,通常是这种情况:Lua代码跑飞,底层亦无响应时,由外部看门狗芯片重启模块。

小提示:

为了调试方便,建议开发者首先在任意lua文件中加入如下代码:

For luaTask:

require”sys”

require”log”

sys.timerLoopStart(function()  log.info(“RAM free size:”, 1024 –
collectgarbage(“count”), “KB”)

                                                                           log.info(“ROM
free size:”, rtos.get_fs_free_size(), “KB”)
end, 5000)

 

For luaScript:

require”sys”

sys.timer_loop_start(function()        print(“RAM free size:”, 1024 –
collectgarbage(“count”), “KB”)

                                                                           print(“ROM
free size:”, rtos.get_fs_free_size(), “KB”) end, 5000)

 

加入如上代码后,模块在运行时,即可间隔5秒打印一次RAMROM使用情况。

通常情况下,如果Lua代码语法错误,或者出现其他问题,Trace中会有如下提示:

Air系列模块重启原因分析及应对策略(二)

报错格式为:

路径/源码文件名:出错行:调用的方法/函数(出错的原因)

堆栈回溯

如图所示,第一行内容提示开发者:/lua/wblist.lua这个文件的121行出错:调用fileSize失败(空值)

后边是堆栈回溯,告知开发者错误函数是如何被调用的。途径是main.lua –> sys.lua run() –> sys.lua saferun() –>
device.lua –> wblist.lua writecard()

如此一来,开发者就可以根据错误提示和堆栈回溯去追根溯源,查找代码错误。

下表是一些常见的错误提示和解决方法:

序号 错误提示 错误原因 解决方法
1 attempt to index %s 变量/函数 索引错误 修改代码
2 attempt to call %s 变量/函数 引用错误 修改代码
3 disp.init: error param width(%d)
height(%d)
disp初始化时,设置了错误的宽、高 修改为正确数值
4 disp.init: pixel depth must be 16 disp像素色深必须是16 修改代码
6 i2c.write: data must be
number,string,table
i2c数据必须是数值、字符串或table 修改数据类型
7 i2c.read: size must < %d i2c读取错误,数据长度超限  
8 bad argument #%d (%s) audio错误的参数 修改传入的参数
9 calling ” LUA_QS ” on bad self
(%s)
audio错误的调用  
10 name conflict for module ” LUA_QS,
libname
命名冲突 修改名称
11 too many results to unpack unpack方法传参错误  
12 attempt to use a closed file 文件已关闭,无法调用 打开文件
13 file is already closed 文件已关闭 打开文件
14 wrong number of arguments 传参 参数 个数错误 检查传参内容
15 string slice too long 字符串过长  
16 attempt to use an invalid  ICONV_TYPENAME Iconv不支持的类型  
17 BUG: Unable to fetch CJSON configuration cjson配置错误  
18 JSON parser does not support UTF-16 or
UTF-32
JSON不支持utf-16utf-32字符编码  
19 Memory allocation error in CJSON
protected call
无法为CJSON分配内存  
20 invalid pin GPIO配置错误,不存在该pin 检查代码和硬件设计手册
21 invalid PIO operation GPIO非法操作  
22 uart.setup can’t be called on virtual
UARTs
UART无法初始化 检查代码,uart.setup相关配置
23 invalid number UART错误的端口号 检查代码,uart.setup相关配置
24 invalid format Uart.setup错误的配置参数 检查代码,uart.setup相关配置

 

除了poweron reason外,我们还可以检查重启后打印的上次重启原因,分析问题所在(luaTask):

Air系列模块重启原因分析及应对策略(二)


通常情况下,如果重启后不存在记录文件,则提示no open(意外掉电导致重启,代码未主动调用接口保存,都可能有这个提示):

Air系列模块重启原因分析及应对策略(二)


如果存在错误文件,则打开该文件,显示内容后,删除该记录文件:

Air系列模块重启原因分析及应对策略(二)

如此一来,我们就能根据记录文件的内容分析啦(上图所示,即软狗引发的重启)。

接下来,我们分析几个典型的具体案例,希望对开发者Debug有所帮助。

一、混用LIB

Air系列模块重启原因分析及应对策略(二)
Air系列模块重启原因分析及应对策略(二)

众所周知,目前LuatLIB库目前有两个版本:第一版名为luaScript,它不含协程,代码也较为陈旧;第二版名为luaTask,它实现了lua的协程,架构更合理,运行也更稳定高效。

 

第二版LIB使用了驼峰命名法。故此,所有函数均和第一版luaScriptLIB不兼容(划重点)。如果开发者如果使用的是第一版的LIB进行开发,但是下载的时候却选择第二版luaTaskLIB,必然会出现错误(反之亦然哦)。

 

例如图中的代码,报错文件是”socketOutMsg.lua”,从文件名的命名法分析,这是一个luaTaskLIB,但是开发者调用的函数名称是misc.getclockstr(),这明显是第一版luaScript LIB 的函数(非驼峰命名法)。所以此处正确的调用方法应是:misc.getClock()

 

开发者如果选择了某个版本的LIB,就要自始至终、始终如一、至死不渝、地老天荒的使用它。不同LIB版本混用就会出现问题。

 

二、语法错误

Air系列模块重启原因分析及应对策略(二)

有的时候碰到这种没头没脑的报错,的确非常头痛。这种情况下建议检查条目:

1、是否存在语法错误:代码块缺少end、缺少)等;

2、是否存在隐含的逻辑错误;

3、源码文件字符编码是否为gb2312

4、源码文件结尾处是否缺少一个新行(所有源码文件尾部必须包含一个内容为空的新行)。

最后一种情况(4),因为报错比较含糊,有可能是最难排查的。所以建议开发者养成一个“结尾随手加上几个新行”的习惯,避免这种情况。

如果以上的1~4都不奏效,那么只能使用“排除法”,依此删减“嫌疑度”最高的代码,下载运行,直到排查出问题所在,再进行分析、修改。

三、“代码跑飞了”?

Air系列模块重启原因分析及应对策略(二)

实际上,图中的问题部分涉及“问题一、混用LIB”。看过上文的读者,应该很轻松就能发现问题所在。

基于lua的协程,使得luaTask更灵活,更稳定,也更强大。所以当协程出现错误时,并不会表现为重启,而是输出错误信息 [E]-[coroutine.resume] xxxx,然后继续执行。由于Trace打印速度极快,而且没有很明显的重启迹象,开发者很容易忽略这个错误。

故此,使用luaTask,模块没有因错重启,Trace也正常打印,但是函数被调用后,却没有正确执行时,开发者应仔细分析LOG有没有出现上述错误。根据错误提示再去Debug

四、内存不足

模块可供lua使用的内存是1024KB,通常情况下是足够使用的。但是如果开发者不小心写了bug,会造成内存不足:

Air系列模块重启原因分析及应对策略(二)


通常情况下,内存不足后,底层会自动重启。

但是某些时候(如图所示),内存不足,但是luaTask没有直接重启,而是继续恢复运行。直到最后彻底失去响应,才会让外部看门狗芯片引导模块重启(poweron reason8):

Air系列模块重启原因分析及应对策略(二)

为了杜绝内存不足这种情况,开发者首先要养成良好的习惯:

·
不要所有函数、变量都写成全局的。开发者应在适当的时候,才使用全局变量,其他情况一律使用local约束;

·
串口收到的数据、http下载的内容等,不要全部放到变量中;如果内容过多,应保存为文件;

·
如果使用变量储存str,不要忘记清空变量;

·
尽量减少全局变量的使用,如果是运行时的常量,可以使用读取配置文件代替变量(请参考nvm demo

·
优化代码逻辑。

排查内存不足的情况,首先要在代码中加入前文提到的打印RAMROM的代码,然后观察Trace打印过程中RAM动态减少的情况。

如果模块在执行某个函数后,内存骤降,那么证明该函数存在问题,需要分析、修改;如果内存缓慢减少,那么应该按照前文所述的方法去更改代码,减少全局变量的使用。

如果开发者遇到底层库报错导致的内存不足,请把Trace文件提供给我司:

Air系列模块重启原因分析及应对策略(二)

五、死循环

由于模块的CPURAM资源有限,所以任何空循环,死循环都会吃尽所有资源。底层发现资源不足是,会自动重启。所以任何时候,都要避免空循环、死循环的情况。

 

由于luaTask的特性,更需要额外注意。如:

require”sys”

require”log”

sys.taskInit(

function()

while true do

此处如果执行的操作很短完成时间内完成(非阻塞等待),可视为死循环

log.info(“loop”, ”test”)

 

为了避免循环吃尽所有资源,可以使用wait,实现1000ms循环一次

sys.wait(1000)

end

end

)

 

六、AT命令执行超时

这种情况较为罕见,通常是lua和底层交互是,底层没有及时的、正确的返回,lua判断AT命令执行超时(通常是60s),自动重启:

Air系列模块重启原因分析及应对策略(二)

这种情况无须担心,是极为罕见的。重启后即可恢复正常运行。如有条件,建议更新到最新底层。

七、无法运行

很多时候,由于开发者一时疏忽,下载lod后忘记下载lua,所以导致无法运行,异常重启。

Air系列模块重启原因分析及应对策略(二)


解决方法也很简单,记得下载lod后,下载lua即可。

结束语

研读Trace输出的内容,是开发者用以Debug的最高效方式,一定要认真分析输出的内容,才能事半功倍。



喜欢 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址