你永久也唤不醒一个装睡的人,可是你能够一巴掌呼醒他。
可假如一个嵌入式体系休眠之后,就犹抱琵琶半遮面,千呼万唤醒不来了呢?笔者担纲开发的中控锁模块就醒不过来了。
1
这个问题现已摧残我整整两天了,搞得我心力瘦弱。合作伙伴一天几个电话,恨不能从手机里边直接跳过来当面责问我:“为什么唤不醒,为什么死睡?”
平常对我爱答不理的领导也一改常态,转而死死地盯着我。宽厚宽厚的我呢,天然也十分严重且惊慌,因为问题十有八九的确出在我写的代码上。
关键是这个问题呈现在立刻大批量供货的前夜,太不是时分了!咱们给某车厂供货的中控锁模块现已走到了小批量供货阶段,前期供货20套却是无惊无险,没发现什么问题,依照流程,接下来要供货100套。
假如阿弥陀佛的话,就再供货200套,再没有什么问题,就进入大批量供货阶段了。届时,合作伙伴开端安稳盈余,领导政绩、奖金到手,不会争功只会揽过的我呢,挥一挥手退到暗地,深藏功与名,全部就万事大吉,只待年月静好了。可是,恰恰在供货100套期间,忘了求菩萨保佑,成果就出事了。
一天,车厂的出产线上下线了装配了咱们的中控锁模块的50辆新车,原本全部顺利,在出产线上操作中控锁没什么问题,匹配学习了遥控钥匙,也能用遥控正常操作。可是到了下线后车厂人员要把新车开回库房时,忽然发现有几台车用遥控钥匙、机械钥匙死活也唤醒不了了!!
事关重大,车厂立马通知了中控锁的供货商—咱们的合作伙伴,合作伙伴立马找到了咱们(中控锁的开发商)领导,领导立马找到了我。我也当即给自己上紧了发条,进入战役状况。
2
眼看到手的政绩和奖金要飞,领导心急火燎,早被晾到一边的我却颇不以为然。
到了现在这个阶段,软件必定没问题,有问题早就测出来了嘛,还能比及现在?必定是中控锁的线束出了问题。
当我把轻描淡写的剖析说与领导时,领导一改往日的温文,一会儿急了:“人家线束供了这么多年了,按你的说法,有问题早就测出来了,还能比及现在?”
年月的风霜早现已消去了我性格中所有的刚硬和炽热,只剩下如水的柔软。看到领导急了,我心中起着嘀咕,脸上泛起笑脸,小心谨慎地对领导言道:“要不我再看一下代码,没准真是哪里出了差错呢?”
得到我的表态后,领导回身踱了开去,一边嘴里想念着得跟车厂承认一下线束有没有问题,一边转过头来再次叮嘱我一番:抓住啊!看着领导那深切的目光和黑黑的眼圈,我用力地址了允许,一个猛子扎进代码的汪洋大海,敏捷游至中控锁的休眠和唤醒之地。
代码的规划思路总是简略并且正确的。中控锁进入休眠之前,设置了两个唤醒条件:①机械解锁信号的上升沿中止唤醒MCU;②定时查看遥控钥匙信号的定时器周期唤醒MCU。当呈现有用的机械锁信号时,或许检测到有用的遥控信号时,中控锁制止这两个唤醒条件并回来正常状况。
在详细的代码完成上,把中控锁的休眠形式处理分成了两部分:中止服务程序和循环体。中止由机械锁解锁开关信号触发,履行完ISR后先回来循环体,再退出休眠形式。循环体中重复休眠和暂时唤醒,在暂时唤醒期间通过三级滤波机制查看是否存在有用的遥控钥匙信号。存在遥控信号时,这个循环体层层地通过三级滤波后,退出休眠形式。
逻辑上明晰,代码也很简略,我反重复复查看了几遍,没看出个子丑演卯来,就按时准点地下班回家了。
第二天上班后,我还没在工位上坐定,还没来得及平复一下自己的炎热劲头,领导就带着于我稀有的笑意猫过来了。不等他开口,宽厚巴交的我就自动汇报了查看代码后没有发现什么问题的状况,no news is good news,可是此刻代码没有问题便是大问题啊!
话音甫落,领导脸上还没来得及打开的笑脸就凝结不动了,他张着口,静静地看着我。
咱们俩就这么站着,不说话,就十分地不夸姣!
城府甚深的领导总算没有说话,他泰然自若地组织了一位搭档搭建了中控锁的测验体系,让他重复测验休眠、唤醒的状况。
3
测验的办法很简略,把电流表串进中控锁的供电线上,看着电流下降到休眠电流规模后,便操作一下遥控钥匙,或许给一个机械解锁信号,看能否履行解闭锁操作。
我在一边冷眼调查着测验人员的操作,心境居然无比地对立,既期望他快点测出来不能正常唤醒的毛病,又盼着最好测验不出来问题。
大半天下来,中控锁反重复复地正常休眠、被正常唤醒,我的心也反重复复地忐忑不定,各样折磨。后来,测验人员的电话响了,我静静回身脱离,一起发现自己居然愈加惊慌了!
刚刚坐到电脑前,测验人员就大呼小叫着跑了过来:“孤寂君,问题再现了!”我就像屁股上安了个绷簧相同,一会儿被凳子弹了起来,待我三步并作两步跨到测验台前时,领导也现已闻声敏捷赶来。
我抓着遥控钥匙一边操作,一边注视着电流表的读数,电流一向安稳在2毫安左右。
问题承认了,的确死活也唤不醒了。
我又一屁股栽倒在凳子上,抬起头来,正赶上领导意味深长的目光。我抿着嘴笑了笑,刚想说点什么,测验台上测验人员的电话又嗡嗡响了起来。
听着了解的手机铃声在耳边环绕,看着手机在桌子上轰动个不断,我回想起测验人员方才打电话时的情形,暗钝的思想再度滚动起来:之前仅仅考虑了机械解锁独自触发唤醒、遥控钥匙独自触发唤醒的状况,没有考虑过遥控信号通过了前两级滤波而此刻机械解锁信号忽然触发履行了ISR这种稀有状况,难道…?
测验人员方才打电话时,因为手机的辐射,RF信号线上呈现了若干有用的射频位,形成RF信号通过了前两级滤波,此刻要在循环体的第三级滤波程序要等候200ms,判别是否是遥控按键信号。
关于嵌入式体系而言,200ms是一个不容忽视的时间段,假使测验人员在这期间企图机械解锁,触发中止履行ISR后会产生什么呢?
我持续扒摆开代码看进去,一丝寒意向我心头袭来。
原本我在ISR中履行了退出休眠形式的函数-ExitSleepMode(这个函数里边会禁能唤醒条件),当ISR履行完毕后回到循环体中时,它会在200ms超时后进入循环体第三级滤波,当然它会发现不是有用的遥控按键信号,所以再度进入休眠。
可是这个时分现已禁能了唤醒条件,这就意味着它再也唤不醒了呀!!
4
人的思想真的很古怪,原本bug分明就在眼前却视若无睹,可是一旦猜到了bug的或许原因,就立马火眼金睛起来。
为了协助读者的了解,笔者给出了下面的伪代码,信任聪明的读者也能看出问题地点。
void interrupt Wake_ISR(void)
{
…
ExitSleepMode();//disable wakeup event
…
}
static void ConfirmRkeWakeUp(void)
{
__delay_ms(200);
if(Rke is valid){
…
ExitSleepMode();
…
}
else{
return to sleep ;
}
}
再让我们加深一下了解。
假定机械解锁信号触发ISR时,循环体正运转到RF信号的第三级滤波程序ConfirmRkeWakeUp之前,MCU会先履行ISR,在ISR中禁能唤醒条件,然后回来循环体中履行ConfirmRkeWakeUp。
ConfirmRkeWakeUp函数延时200ms后,判别这200ms之间有没有有用的遥控钥匙信号,明显这里是没有的,所以Return to sleep。
可是,这个时分唤醒条件现已被禁能了(在ISR中被禁能了),体系就永久不会被唤醒了。
眼尖的读者或许会疑惑,这种毛病之前为什么没有测验出来?
因为依照之前的测验条件,这种状况产生的几率十分小:循环体内履行ConfirmRkeWakeUp函数之前需求通过两层RF滤波,这要求中控锁的RF信号线上必须在较短的时间内存在较多的契合宽度要求的RF信号位,不然就不会履行ConfirmRkeWakeUp这个函数;平常用机械钥匙解锁时,尽管ISR中禁能了唤醒条件,可是因为不会履行ConfirmRkeWakeUp,ISR回到循环体之后,体系仍然会退出休眠。
平常用遥控钥匙解锁时,不管期间有没有产生机械解锁ISR,终究都会履行ConfirmRkeWakeUp并退出休眠。
所以,只要无效的遥控按键信号触发履行ConfirmRkeWakeUp函数时机械解锁信号一起有用,才会触发这种毛病。
轿车出产线上为什么测验出来这种毛病了呢?
那是因为在出产线上装配了中控锁的车太多了,产线后端的中控锁模块进了休眠之后,用机械钥匙唤醒时很简单被其它车的遥控钥匙操作误触发,导致循环体履行到ConfirmRkeWakeUp上来。
可是其它车的遥控钥匙关于本车来说是无效的,所以,依据上面的原因,毛病就呈现了。
结语
定位了毛病的原因之后,我不由又洋洋得意起来,‘这么高档的bug都被我逮出来了!’。恰似全然忘记了这个毛病便是我自己埋下的坑。
过后,领导让我写总结原因时,我认识到了这种毛病背面的深层次原因在于中止和循环体的不登对:中止服务程序完毕后必定回到主循环体中被中止的方位;嵌入式体系中,中止或许产生在主循环体的任何方位;ISR和循环体程序之间不存在履行时间的先后顺序联系,先后次第不同或许导致不同的运转成果;因为ISR产生时循环体或许会履行到任何代码方位上,假如代码规划地不谨慎就有或许会形成问题!
煮熟的鸭子终究没有飞走,领导又笑意盈盈地踱了过来,跟我请教毛病的原因。看着他那被行将到手的奖金鼓动地有些肿胀的胸膛,我一边静静地想念着‘狡兔死喽啰烹,飞鸟尽良弓藏’,一边悠悠地说了一句总结陈词:中止和主循环不登对,体系会一向休眠久睡!