花儿开,鸟儿叫,早上上班的路迢迢。风儿吹,阳光照,为国作业的豪情万丈高。
那日,洒家虎虎生风地走在上班的路上,正好碰上一位父亲领着女儿去上幼儿园。看得出来,小家伙儿的起床气还没有彻底散失,耷拉着脑袋,慢腾腾地踢踏着。爸爸一边急火火地拽着女儿的小臂膀往前赶,一边跟她说着什么。
洒家正待从这对父女俩身边走过期,正听得爸爸弯着腰对女儿说:“不上幼儿园怎样上小学呀?”小丫头片子奶声奶气地说不想上小学。爸爸不认为然地持续说教着:“不上小学怎样上大学呀?”
‘恩?小学之后不该是初中吗,还有高中呐!’我正在心里犯着嘀咕,一声响亮的哭腔便划破空气,直冲耳膜而来。回头一看,小家伙正一边甩着臂膀打爸爸的屁股,一边咧着大大的嘴巴哭着说:“我什么学都不想上!!”
我初觉好笑,继而感到有些悲痛。看着她那梨花带雨的姿态,一股惆怅在我心底潮起:你认为我乐意上班的吗?
1
顺畅出差回来后第一天的上班日子清闲而安闲,可以东转转西逛逛,和这个搭档打个闲茬,和那个同仁热切但放松地评论技能。
可是假如出差不顺畅,回来第一天的上班日子就没有那么轻松美好了。在邂逅不肯上幼儿园的女娃娃那天,我正是这样的状况。
这次出差的作业任务是到汽车厂进行总线测验,笔者动身时怀着胀得鼓鼓的决心,带着游山玩水的闲情逸致,回来时揣着灰溜溜的挫折感,和不知如何是好的懊丧。
几个月前去测验时,分明测得好好的,这一次,竟然测验失利了!
测验报告中那几个夹在绿色OK项目中心的NOK项,发着悠悠的红光,带着冷冷的笑意,让我的寒意从头顶直接凉到了大地。
点开这几个NOK项的测验数据,一行行标记取报文收发时刻、收发方向、ID、数据场的数据目不暇接地扑面而来。依据过错提示,笔者产品发送报文的周期性没有满足要求。我拖着鼠标从左拖到西,又从上拖到下,总算发现,有一条以50ms为周期固定发送的报文,有那么一次,没有及时地发出来。
各种思路向我的脑际涌来,洒家稳了稳心神,首先把置疑的目光放到了CAN通讯代码的共同性上面。假如两个版别的CAN通讯代码不共同,把代码改回去就还有测验通过的期望!!
许是这几个月来不小心改了CAN通讯代码中的哪个模块或哪个函数呢?
我刻不容缓地调出了几个月前来做第一次测验时的代码,用Beyond Compare比照东西和这次的测验代码进行了比对。
除了这几个月中增加的许多其它模块的代码,CAN通讯代码竟然是共同的。刚刚升起的一丝期望被无情地浇灭了。通讯代码共同意味着,是这几个月来增加的不知道哪段代码改变了这次的测验成果。
费事大了!这几个月来添了那么多代码,鬼才知道到底是哪块影响了倒运的CAN通讯。
在汽车厂搞了一天,依然茫无头绪,测验MM也开端置我的美色于不管,显露不耐烦的神色来,所以我只好灰溜溜地回了公司。
2
听说篮球和足球比赛有主场、客场之分,在自己的主场上,在一众球迷的呐喊助威下,在家乡父老的气氛烘托下,球队简略比出好的成果来。
回到公司的我,尽管听不到搭档们的鼓掌声,可是,回到自己了解的地盘,战斗力也直线上升。
我戴上耳机,耳旁响起舒缓的轻音乐,在似乎与世隔绝的静寂中,我小心肠调查着那几个测验NOK项的测验数据。
很快,这些数据的特征浮现在洒家的面前。
在这几项测验中,测验软件发送了许多优先级或高或低的无关报文,相比之下,之前的测验中也发送了许多报文,可是都是产品用得到的报文。
不同之处找到了,问题的原因天然也就很简略找到了。为了协助读者了解,笔者先简略介绍一下CAN报文接纳的处理程序:
①总线上接纳到报文时,MCU被触发报文接纳中止。
②进入ISR程序后,MCU会拿接纳到的报文ID和产品标准所界说的需求解析的ID顺次进行比较。
③通过若干次比较后,假如接纳报文ID和需求解析的ID共同,把报文存入接纳缓冲区,发送“接纳到新报文”信号。假如不共同,标明接纳到的是无关报文,MCU直接丢掉报文。
在洒家这个产品中,需求解析大约20条报文。为了简略,笔者依照ID从小到大的次序进行比较。明显,无关报文需求进行20次比较,终究被MCU丢掉掉,相关报文进行比较的均匀次数则为10次。实际上,测验软件给出的那几个OK项测验中,最多的比较次数也没有超越10次。
写到这儿,问题的原因呼之欲出了!在许多高频次报文的冲击下,MCU一向忙于进行ID的比较匹配。无关报文的冲击力气尤甚,由于MCU进入报文接纳ISR后,每次都要进行多达20次比较!!
深谙摩尔定律的看官或许笑了,现在MCU功能这么高,20次比较算逑?!
3
笔者喜爱拿数听说话,这回咱就用初中数学知识掰扯掰扯。
CAN报文的数据帧由7个不同的位场组成:帧开始、裁定场、操控场、数据场、CRC场、应对场、帧结束。
其间,帧开始标志数据帧和长途帧的开始,由一个独自的“显性”位组成。裁定场包含辨认符和长途发送恳求位(RTR)。辨认符的长度为11位。操控场由6个位组成,包含数据长度代码和两个将来作为扩展用的保存位。数据场由数据帧中的发送数据组成。它可认为0~8 个字节。CRC场包含CRC序列(CRC SEQUENCE),这以后是CRC界定符(CRC DELIMITER)。CRC序列为15位,CRC界定符包含一个独自的“隐性”位 。应对场长度为2个位,包含应对空隙(ACK SLOT)和应对界定符(ACK DELIMITER)。帧结束由一标志序列界定。这个标志序列由7 个“隐性”位组成。
所以一个8字节的数据帧的位数为1(帧开始)+ 12(裁定场)+ 6(操控场)+ 64(数据场)+ 16(CRC场)+ 2(应对场)+ 7(帧结束)= 108位。
报文之间存在帧间空间INTERFRAME SPACE。帧间包含间歇场、总线闲暇的位场。间歇场包含3 个“隐性”的位。
所以,一个8字节的数据帧至少需求(108+3+1)* bitrate的时长,关于125kbps,需求0.896ms。关于500kbps,需求0.224ms。
不巧的是,笔者的产品需求面对的便是500kbps通讯速率的总线通讯。
那么问题来了,0.224ms来一次中止,每次中止履行20次数据比较,你说MCU累不累?
累,MCU累得都快冒烟了!
剑客的最高境地是人剑合一,人便是剑,剑便是人。洒家远没有到码农的最高境地,但也高山仰止,知道要善待MCU,才干终究到达人机合一。
看着累得偶然愣了神忘了发送报文的MCU,笔者在疼爱又无法的泪眼模糊中苦苦思索着,怎样给MCU减减负呢?
4
这儿要做的作业一言以蔽之,便是针对频频中止的ISR,优化它的履行时刻,卸掉MCU的担负。
看着那20个需求进行比较的报文ID,洒家眉头一皱,计上心来。
CAN报文ID是11位,头三位的取值为0-7,相当于将CAN报文ID的取值区间区分成了八段,分别是0-0xff、0x100-0x1ff、0x200-0x2ff。。。0x700-0x7ff。
假如将CAN报文ID右移八位,得到头三位取值,就可以知道这个报文ID处于这八段取值区间的哪一段,然后再到这个段内进行比较,比较次数不就下降许多了吗?
比方说,产品需求解析的0x700-0x7ff段的ID有0x701、0x7df两个报文,接纳到一个0x745的无关报文时,之前的比较次数是20次,现在是履行一次8位移位,然后进行2次比较。
只需求履行一次移位运算,比较次数从20次猛然下降到了2次!!
我被这种功率的提高起伏惊呆了。仅仅一个十分简略的办法,就得到了这么好的作用!
带着修改后的代码,怀着一丝忐忑九分坦荡,洒家又直奔汽车厂测验去了。
测验通过后,测验MM向我投来赞赏的目光,我回之以笑意,心中实则感慨万千。
时刻是世界上最为顽强的东西,它一往无前,绝不回头。可是鲁迅先生说:时刻就像海绵里的水,挤一挤总会有的。
MCU的才能也是如此,只需你怀着一颗精雕细镂的心,好好地规划代码,比方关于频频中止的ISR,履行时刻细心优化,就能很好地驾御它,发挥它的潜力。
套用鲁迅先生的话,便是:
MCU的功能便是海绵里的水,挤一挤总会有的!