第9章 嵌入式系统设计与调试
9.1 嵌入式系统设计流程
在我工作的第二年(大约10年前),我第一次私下完全独立地设计制作了一款模块冷水机组单片机集中控制系统,由单片控制系统根据环境的实际负荷智能控制多台冷水机组协调平衡运行。我记得自己是按以下步骤开展工作的:
1)详细了解控制对象,制定出控制器的模拟输入/输出数量以及数字输入/输出数量;
2)制定输入与输出的控制逻辑关系;
3)参考以前类似产品的设计资料;
4)制定出整体设计方案;
5)广泛查阅相关芯片的数据手册以及市场供应情况;
6)完成芯片选型,采购芯片;
7)绘制电路原理图;
8)照芯片制作封装图,绘制PCB图;
9)找制板厂制作PCB电路板,自己开始写程序代码(都是汇编);
10)自己焊接;
11)使用仿真调试器进行调试;
12)调试完之后对原理图、PCB图和源代码作相应修改;
13)进行第二次制板;
14)再次调试;
15)结束。
经过以上步骤,克服了种种困难,我自己独立设计制作的第一个产品就这样诞生了,而且得到了公司的全额资金支持,成为公司自研项目,替换外购产品。这是对我的最好认可,也是对我自信心的最大激励。我能做到,相信所有有志做点事情的读者同样能够做到。开了个好头,后面的事就顺理成章了,即使碰到再大的困难也都是能够克服的。
9.2 嵌入式系统硬件原理设计与审核
以下是我根据10多年电路设计与调试经历总结出的一点经验和感想,姑且叫它“电路原理图设计审核规范”吧,只是一家之言,摘录到这里仅供读者参考。
1)详细理解设计需求,从需求中整理出电路功能模块和性能指标要求。
2)根据功能和性能需求制定总体设计方案,对CPU进行选型,CPU选型有以下几点要求:
a)性价比高;
b)容易开发:体现在硬件调试工具种类多,参考设计多,软件资源丰富,成功案例多;
c)可扩展性好。
3)针对已经选定的CPU芯片,选择一个与我们需求比较接近的成功参考设计,一般CPU生产商或他们的合作方都会对每款CPU芯片做若干款开发板进行验证,比如AMCC的PPC440EP就有yosemite和bamboo两款开发版。厂家最后公开给用户的参考设计图虽说不是产品级的东西,也应该是经过严格验证的,否则将会影响到他们的芯片推广应用。纵然参考设计的外围电路有可推敲的地方,CPU本身的管脚连接使用方法也绝对是值得我们信赖的,当然如果万一出现多个参考设计某些管脚连接方式不同的情况,我们可以细读CPU芯片手册和勘误表,或者找厂商确认。另外在设计之前,最好能外借或者购买一块选定的参考板进行软件验证,如果软件验证没有问题,那么硬件参考设计也是可以信赖的。但要注意一点,现在很多CPU都有若干种启动模式,我们要自己选一种最适合的启动模式,或者做成兼容设计。
4)根据需求对外设功能模块进行元器件选型,元器件选型应该遵守以下原则:
a)普遍性原则:所选的元器件要是被广泛使用验证过的,尽量少使用冷门、偏门芯片,减少开发风险。
b)高性价比原则:在功能、性能、使用率都相近的情况下,尽量选择价格比较好的元器件,降低成本。
c)采购方便原则:尽量选择容易买到、供货周期短的元器件。
d)持续发展原则:尽量选择在可预见的时间内不会停产的元器件。
e)可替代原则:尽量选择pin to pin兼容芯片品牌比较多的元器件。
f)向上兼容原则:尽量选择以前老产品用过的元器件。
g)资源节约原则:尽量用上元器件的全部功能和管脚。
5)对选定的CPU参考设计原理图外围电路进行修改。修改时对于每个功能模块都要找至少3个相同外围芯片的成功参考设计,如果找到的参考设计连接方法都是完全一样的,那么基本可以放心参照设计,但即使只有一个参考设计与其他的不一样,也不能简单地按少数服从多数的原则,而是要细读芯片数据手册,深入理解那些管脚含义,多方讨论,联系芯片厂技术支持,最终确定科学、正确的连接方式,如果仍有疑义,可以做兼容设计。这是整个原理图设计过程中最关键的部分,我们必须做到以下几点:
a)对于每个功能模块要尽量找到更多的成功参考设计,越难的应该越多,成功的参考设计是“前人”的经验和财富,我们理当借鉴吸收,站在“前人”的肩膀上,也就提高了自己的起点。
b)要多向权威请教、学习,但不能迷信权威,因为人人都有认知误差,很难保证对哪怕是自己最了解的事物总能做出最科学的理解和判断,开发人员一定要在广泛调查、学习和讨论的基础上做出最科学正确的决定。
c)如果是参考已有的老产品设计,设计中要留意老产品有哪些遗留问题,这些遗留问题与硬件哪些功能模块相关,在设计这些相关模块时要更加注意推敲,不能机械照抄原来设计,比如我们老产品中的IDE经常出问题,经过仔细斟酌,广泛讨论和参考其他成功设计,发现我们的IDE接口有两个管脚连线方式确实不规范。还有,针对FGPI通道丢失视频同步信号的问题,可以在硬件设计中引出硬件同步信号管脚,以便进一步验证,更好发现问题的本质。
6)硬件原理图设计还应该遵守一些基本原则,这些基本原则要贯彻到整个设计过程,虽然成功的参考设计中也体现了这些原则,但因为是“拼”出来的原理图,所以我们还要随时根据这些原则来设计审查原理图,这些原则包括:
a)数字电源和模拟电源分割。
b)数字地和模拟地分割,单点接地,数字地可以直接接机壳地(大地),机壳必须接地,以保护用护人身安全。
c)保证系统各模块资源不能冲突,例如:同一I2C总线上的设备地址不能相同等。
d)阅读系统中所有芯片的手册(一般是设计参考手册),看它们未用的输入管脚是否需要做外部处理,是要上拉、下拉,还是悬空,如果需要上拉或下拉,则一定要做相应处理,否则可能引起芯片内部振荡,导致芯片不能正常工作。
e)在不增加硬件设计难度的情况下尽量保证软件开发方便,或者以较小的硬件设计难度来换取更多方便、可靠、高效的软件设计,这点需要硬件设计人员懂得底层软件开发调试,要求较高。
f)功耗问题,设计时尽量降低功耗。
g)产品散热问题,可以在功耗和发热较大的芯片增加散热片或风扇,产品机箱也要考虑这个问题,不能把机箱做成保温盒,电路板对“温室”是感冒的。还要考虑产品的安放位置,最好是放在空间比较大,空气流动畅通的位置,有利于热量散发出去。
7)硬件原理图设计完成之后,设计人员应该按照以上步骤和要求首先进行自审,自审后要有95%以上的把握和信心,然后再提交给他人审核,其他审核人员同样按照以上要求对原理图进行严格审查,如发现问题要及时进行讨论分析,分析解决过程同样遵循以上原则和步骤。
8)只要开发和审核人员都能够严格按照以上要求进行电路设计和审查,我们就有理由相信,所有硬件开发人员设计出的电路板第一版成功率都会很高的,所以我提出以下几点:
a)设计人员自身应该保证原理图的正确性和可靠性,要做到设计即是审核,严格自审,不要把希望寄托在审核人员身上,设计出现的任何问题应由设计人员自己承担,其他审核人员不负连带责任。
b)其他审核人员虽然不承担连带责任,也应该按照以上要求进行严格审查,一旦设计出现问题,同样反映了审核人员的水平、作风和态度。
c)普通原理图设计,包括老产品升级修改,原则上要求原理图一版成功,最多两版封板,超过两版将进行绩效处罚。
d)对于功能复杂,疑点较多的全新设计,原则上要求原理图两版内成功,最多三版封板,超过三版要进行绩效处罚。
e)原理图封板标准为:电路板没有任何原理性飞线和其他处理点。
9)制定上述规范的目的和出发点是为了培养硬件开发人员严谨、务实的工作作风和严肃、认真的工作态度,增强他们的责任感和使命感,提高工作效率和开发成功率,保证产品质量。希望年轻的硬件开发人员能在磨炼中迅速成长起来。
对于复杂的PCB板设计,如高频多层板一般都请专人布线,因为复杂的PCB板涉及电磁兼容和电磁干扰方面的问题,这是一门高深的学问,除了一些基本的注意事项外还有一些特殊的防护措施,比如设计时使用一些专门的电磁兼容芯片等,感兴趣的读者可以看一些电磁理论方面的书籍。
9.3 硬件设计工具软件
目前设计原理图一般使用Protel99SE或者OrCAD Capture软件。而PCB布线一般使用Protel99SE、PADS或者Allgero(Cadence),其中Allgero的综合功能最强,有非常强的硬件仿真功能,受到越来越多硬件设计工程师的青睐。
Protel99SE的安装比较简单,网上有只需双击一个安装图标就可以一次完成安装的版本。而Cadence和PADS的安装有时会碰到一些麻烦,主要是安装license的问题,我就曾经碰到过,但只要读者耐心细致一点总是能成功的:只要把有效license.txt文件放到PADS安装目录下,然后在安装license时,把路径指到该文件就可以了。cadence的license文件则是做好了的license.lic文件,只要把它放到某个目录下,再设置Windows环境变量LM_LICENSE_FILE指到这个文件就可以了。
9.4 嵌入式系统调试仿真工具
嵌入式硬件系统设计出来后就要进行调试,不管是硬件调试还是软件调试或者程序固化,都需要用到调试仿真工具。
随着处理器新品种、新型号的不断涌现和不断更新,目前市面上的嵌入式系统调试仿真工具也层出不穷,这些调试仿真工具因其功能、性能、通用性的不同价格也相差非常悬殊,从几十元的简易JTAG调试器到几万元甚至几十万元的高端调试仿真器应有尽有,以前这方面的工具大部分都是进口的,现在国内有些公司也开始开发这方面的工具,而且性价比很好,只是国内做的大部分都是专用的,通用的比较少,因为通用的应用也很少,而且价格昂贵。
下面列举一些我曾经用过的调试仿真工具:
1)MCS-51单片机调试仿真系统MDS-55-B5,由三环电子生产;
2)调试PPC860、IXP425和PPC440EP用的BDI2000(进口);
3)调试SB1250(MIPS)和PPC405GP用的Risc Watch Debugger(进口);
4)调试PPC860用的EST ICE(进口)和BDM Probe(进口);
5)调试MC68K用的Code Cruiser加串口;
6)调试S3C44B0和S3C4510用的简易JTAG调试器,用于S3C44B0和S3C4510调试的简易JTAG调试器有两种,一种是与SDT2.51软件配合使用简易JTAG调试器,另一种是与ADS1.2配合使用简易JTAG调试器(不过我没有用成过,因为我下载的ADS1.2不能用),叫做Wiggler线缆,第10章中的简易JTAG线缆烧写器就是指Wiggler,这两种简易JTAG的Protel99SE版原理图和PCB图都可以从本书附带的光盘中找到。
9.5 嵌入式系统调试诊断方法
嵌入式系统开发过程实际上就是一个调试诊断的过程,而且调试诊断将一直伴随着一个产品的终身,即使是最成熟的产品也偶尔会出现这样或那样的问题,这都需要开发人员去诊断、排查。
嵌入式系统的调试包括硬件调试、软件调试以及综合调试。硬件调试一般是指系统刚开发出来时上电前后的检查,包括:
1)上电前检查电源和地是否短路,目视检查是否有虚焊、漏焊;
2)上电后检查时钟线上的频率和波形、幅度是否正常,各电源电压是否稳定正常,各芯片温度是否正常,各指示灯是否正常。
软件调试一般是指保证硬件一切正常的情况下验证程序执行的时序是否正确,逻辑和结果是否与设计要求相符,能否满足功能和性能要求等。软件调试的方法有很多,包括:
1)用指示灯跟踪调试;
2)用串口打印调试;
3)用简单的调试器进行汇编代码级调试;
4)用比较高端的调试器进行源代码级调试;
5)用仿真器进行硬件仿真。
上述单纯的硬件调试或软件调试都是相对比较简单的,困难的是综合调试。下面我先举一些自己在工作中曾经碰到的疑难问题,然后再从中归纳出一些一般的调试方法和注意事项。
例1:我们自主设计制作的PPC860(Motorola)网络引擎平台的调试已接近尾声,同一批生产的4块板子都通过了全部软件测试,于是又去焊了第二批,可是在第二批板子中有1块板子的FEC不能正常工作,我们几个软件和硬件工程师使用了各种手段,重新看了多遍芯片手册,还是没找出原因,于是把板子发回工厂重新焊接BGA,可是回来问题还是照样存在,没办法最后打算将这块板子当做个样处理,把板子上的芯片都焊下来。按常理来说这种做法很符合逻辑,因为元器件都是一样的,板子也是一批的,那就可能是这块板子的某个地方焊接不好,但又不好查,反复重新焊接可能会把主板焊坏。后来有人从PPC860芯片上用放大镜都要睁大眼睛才能看清的字符上(据说我国第一代国产高端处理器芯片“寒心”就是某“科学家”将“摩托”同一类型芯片上的这些字母磨掉后刻上“寒心一号”摇身一变造出来的!!!)发现这块板子的CPU版本号是“D4”,而其他板子的CPU版本号是“D3”,可芯片手册上并没有这两个版本之间的比较说明,从网上找到PPC860的勘误手册,发现在PPC860TZP50D4版本中,ECNTRL寄存器增加了一个叫FEC_PIN_MUX的位(bit2)来控制FEC各管脚的复用功能,如果要使用FEC就必须将该位设置为1,所以要在FEC的相关程序中加上ECNTRL |= 0x00000004语句行。
例2:当我调试业余自制的MC68VZ328板子时,电路板硬件检查没有问题,用Code warrior通过串口往flash中烧制编译好的uClinux程序也一切正常,但是重新上电,发现串口没有任何数据,用万用表检查(当时自己没有示波器等“先进设备”)也没查出结果,然后每天上下班把这块板子放在包里,没事就拿出来瞪大眼睛看看,看着也不免窝火,但有一天却发现一个标着电阻符号的地方却焊上了电容,回到家把电阻换上去再上电,串口一下就打印出uClinux的启动信息,呵,那滋味,比喝了蜂蜜都甜,当然当时也是因为没有太多经验,如果这问题放现在,估计一天内肯定解决掉。另外在初次调试自制的S3C4510开发板时,就是不能从串口输出字符,费了半天时间才发现把串口电平转换芯片max3232cse的第6脚上的旦电容极性焊反了。
例3:在调试SB1250嵌入式服务器主板时,由于使用的是DDR1代内存条,数据线和时钟线上串并联的去耦电容电阻相当多,第一批焊回来的板子几乎没有一块能够顺利进入CFE(BIOS)菜单界面的,检查时钟波形和电源与借用的DEMO板相比都很好,我把主板上DDR DIM槽周围的那些去耦电阻电容都全部用烙铁重新过一遍锡,嘿嘿,还真管用,这种方法屡试不爽,而且在后面调试PCI和HT总线时使用这招也很有用,可能是因为SB1250系统是高频电路,对焊接要求比较高,稍微有一点漏焊或者虚焊都不行,我是这样认为的。
例4:在一个使用实时时钟芯片SD2000的应用系统中,经常会出现读出的时间被复位到“2000年1月1日”的情况,我用自己编写的测试程序经过多次测试发现,按照SD2000芯片手册中的时序进行连续读写确实会经常出现复位现象,好像是芯片错把读写时序当成了复位操作时序,而且每次必出,所以我感觉到芯片本身应该有Bug,于是告诉同事可能是芯片本身有问题,让他跟厂家联系,但因为这个芯片在老产品中用了比较长的时间,所以同事不太认同我的看法,但还是与SD2000厂家取得了联系,厂家经过两天专门强化测试后通知我们“SD2000本身确实有Bug,可能因为干扰导致芯片复位到2000年1月1日”。
例5:在用PNX1700(DSP)处理器设计成的音视频开发平台上,常会出现CVBS输出黑白图像(应该是彩色)或颜色不正常现象,于是先详细阅读CVBS输出芯片AVS3169的手册,然后用示波器测量3169芯片的时钟管脚,在测量的过程中经常会出现颜色恢复正常的现象,再做多次测试发现这种现象是由于将场同步VSYNC信号与相邻的数据线Data7短路造成的,再测试发现将VSYNC与其他数据线(Data[0:6])任一根短接一下都可以恢复正常,再用视频时钟信号CLK与数据线短接一下有时也能恢复正常,但有时也不能恢复,所以怀疑是视频场同步信号有问题。顺着这根线索查了一下AVS3169的VSYNC信号与PNX1700的连接方式,发现在用CVBS输出时,PNX1700上与AVS3169的VSYNC信号相连的引脚是输出QVCP_VSYNC信号,检查VO输出模式设置没有问题,再查QVCP的设置,看哪个寄存器能控制QVCP_SYNC信号,发现在QVCP_CONTROL(0x10e020)寄存器中有对HSYNC和VSYNC的控制,用命令在线修改了直接相关的该寄存器中4个位的值,但没有任何效果,再在整个PNX1700芯片手册中查找关键字VSYNC,发现在398页有对QVCP VSYNC设置要求的描述:该寄存器的bit1(Master)要求设成1,即从模式,而我们现在是设成0,即主模式,我把该位改成1后屏幕出现黑屏,没有任何显示,再把这位恢复到0,竟然出现了颜色,屡试不爽,仔细研究这个寄存器的bit1和bit0分别是控制屏幕时钟发生器(STG)工作模式(主/从)和STG的复位,分析觉得在系统上电后对QVCP初始化之前先把QVCP的STG置成从模式并且复位STG,然后再用原有的初始化程序,这样应该可以解决视频信号的时钟和数据不同步问题,所以在主程序中初始化QVCP之前加入MMIO(0x10e020) = 0x20050006行,测试果然不再出现上述问题,问题解决;并顺势延伸一下,以前用SAA7105做CVBS输出时偶尔也会出现屏幕顶部显示不正常问题应该与这个问题一样,所以用上述相同的方法修改程序后对SAA7105 CVBS输出进行强化测试(每8秒钟重新启动一次,强化测试3天),结果没有再出现显示不正常现象。
例6:同样是PNX1700音视频开发平台上遇到的问题,VGA输出时OSD菜单会抖动,最先想到的方法是把OSD的scaler改用QVCP来做而不是MBS来做,这样在1500上会减轻OSD抖动现象,几乎不出,但在1700上测试效果还是很不好,抖动仍然很厉害,后来安排同事将1500种DDR时钟的工作频率从166MHz提高到200MHz,并告诉他需要改哪个模块的哪几个寄存器,这时正好是用VGA做视频输出(一般情况是用CVBS做视频输出,但因为此时正在跟踪VGA中OSD抖动问题,所以用了VGA输出模式)来调DDR工作频率的,在同事修改DDR寄存器过程中我却发现OSD怎么不抖了,仔细研究同时修改过的寄存器相关位的定义,发现在DDR模块中有两个寄存器与DDR仲裁相关,一个是ARB_HRT_WINDOW(0x65184,DDR仲裁硬件实时窗口),另一个是ARB_CPU_WINDOW(0x65188,DDR仲裁CPU窗口),将这两个寄存器分别设置成ARB_HRT_WINDOW = 0xffff及ARB_CPU_WINDOW = 0x0就不会出现OSD抖动,因为在这种设置情况下DDR对DMA的占有权高于CPU对DDR的拥有权,DDR可以抢断CPU,原来的设置使CPU可以抢断DDR占有DMA。其实在发现问题VGA中的OSD抖动问题之初我也找过与memory相关的寄存器设置,因为根据以前经验和习惯思维,DDR配置寄存器只是负责DDR部分,而memory与CPU之间关系的寄存器应该在系统寄存器中,所以没有去查找DDR配置寄存器,可是在这一例子中却偏偏在DDR配置寄存器中。
从上述几个例子中我们可以总结归纳以下几点调试方法和注意事项:
1)加深理解法:加深理解包括加深对硬件和软件的理解,加深对硬件的理解主要是详细阅读相关的芯片数据手册,而加深对软件的理解是因为现在开发嵌入式系统并不是所有程序都需要自己编写,很多都是已经做好的,直接从网上获取或者采购获得,但这些软件不一定是完全针对我们自己的目标板的,所以在使用过程中经常会发现一些问题,特别是底层软件,而一旦出现问题,开发人员首先必须了解出现问题的代码。只有建立在对相关硬件和软件深入理解的基础上才可能做出更符合实际的判断,才可能更好地解决问题。
2)比较法:比较的方法有很多,比如将同样的软件放在两个类似但不相同的硬件平台上运行比较现象;将两个不同版本的软件放在同一个硬件平台上运行比较现象;将相同的软件放到相同批次但不同的两个硬件平台上运行比较现象。对于一些不是很隐蔽的问题通过比较法通常能得到不错的效果。
3)分解法:当碰到分析起来比较复杂、可能有很多因素的问题时,可以把问题分成解几个小问题来测试诊断,比如编写几个单独的小测试程序对各种可能因素进行排查测试,根据这些测试结果再进行科学判断。
4)软硬件结合法:这种方法是需要一定灵感和悟性的。比如上面的例5,在测试过程中,可以在不破坏硬件的前提下临时改变一下硬件的状态(比如该例中将数据线和时钟线短路),看问题现象会不会有所变化,如果有,那么多做类似试验找出变化规律和关键因素,然后再进行分析解决。在底层软件开发中,对于时序要求严格的硬件模块的软件编程要特别注意,一旦程序的时序出了问题,而这部分软件已经与其他系统软件融合到一起,那么这种软件让别人去检查是很难查出问题的。
5)诊断、排故要建立在大量实验的基础之上,要多动手,不能光知道臆想,不愿实际操作,还美其名曰“善于思考和分析”。嵌入式系统开发是一门实践性很强的科学,需要在实践中总结出事物客观规律,从而更好地认识和利用它们,让它们更好地按我们的意图工作。
6)嵌入式系统开发调试要求开发人员有严谨细致的工作态度,决不放过调试过程中发现的任何一点蛛丝马迹,因为它很可能就是打开潘多拉宝盒的钥匙。
7)要有实事求是的工作作风,要有敢于怀疑一切的精神和勇气,我们理当尊重权威和前人的科技成果,但当出现矛盾时我们更应该相信实验结果,这样科学才会进步。
8)要勇于挑战自我,抛开习惯性思维和成见,拓宽思路,多角度分析问题。
9)嵌入式系统开发特别是底层软件和操作系统内核开发因为需要同时跟软件和硬件打交道,所以是一件比较艰苦的工作,很有挑战性。即使我们各方面都做得非常好,考虑得非常细致周全,目标系统仍然可能跟我们开一些小小的玩笑,我们经常会碰到一个非常小的问题困扰我们几天甚至几周的时间,这期间我们可能茶饭不思、夜不能寐,因此嵌入式系统底层软件开发人员不但要有平和的心态,且具备一定的耐心和毅力,还要有勇于克服一切困难的勇气和信心!只要我们做得足够好,那么可能解决一个具体疑难的过程带有一定偶然性,但我们终将排除所有阻碍!
所以说,嵌入式系统调试过程就是一个更加深入了解我们的目标系统以及系统中的每个单元模块特性的过程,就是一个锻炼我们的逻辑思维和分析推理能力的过程,就是一个开拓思路、向习惯思维和权威挑战的过程,就是一个培养严谨细致的工作态度和实事求是工作作风的过程,就是一个锻炼我们耐力和毅力的过程,最终是一个学习进步的过程!
嵌入式系统调试诊断能力的提升是一个长期实践、积累、提高的过程!