星期二, 五月 22, 2007

在一个大的电容上还并联一个小电容的原因[转]

大电容由于容量大,所以体积一般也比较大,且通常使用多层卷绕的方式制作,这就导致了大电容的分布电感比较大(也叫等效串联电感,英文简称ESL)。

电感对高频信号的阻抗是很大的,所以,大电容的高频性能不好。而一些小容量电容则刚刚相反,由于容量小,因此体积可以做得很小(缩短了引线,就减小了ESL,因为一段导线也可以看成是一个电感的),而且常使用平板电容的结构,这样小容量电容就有很小ESL这样它就具有了很好的高频性能,但由于容量小的缘故,对低频信号的阻抗大。

所以,如果我们为了让低频、高频信号都可以很好的通过,就采用一个大电容再并上一个小电容的方式。

常使用的小电容为 0.1uF的瓷片电容,当频率更高时,还可并联更小的电容,例如几pF,几百pF的。而在数字电路中,一般要给每个芯片的电源引脚上并联一个0.1uF的电容到地(这个电容叫做退耦电容,当然也可以理解为电源滤波电容,越靠近芯片越好),因为在这些地方的信号主要是高频信号,使用较小的电容滤波就可以了。

0 欧姆电阻的作用(转载)

大概有以下几个功能:

①做为跳线使用。这样既美观,安装也方便。

②在数字和模拟等混合电路中,往往要求两个地分开,并且单点连接。我们可以用一个0欧的电阻来连接这两个地,而不是直接连在一起。这样做的好处就是,地线被分成了两个网络,在大面积铺铜等处理时,就会方便得多。附带提示一下,这样的场合,有时也会用电感或者磁珠等来连接。

③做保险丝用。由于PCB上走线的熔断电流较大,如果发生短路过流等故障时,很难熔断,可能会带来更大的事故。由于0欧电阻电流承受能力比较弱(其实0欧电阻也是有一定的电阻的,只是很小而已),过流时就先将0欧电阻熔断了,从而将电路断开,防止了更大事故的发生。有时也会用一些阻值为零点几或者几欧的小电阻来做保险丝。不过不太推荐这样来用,但有些厂商为了节约成本,就用此将就了。

④为调试预留的位置。可以根据需要,决定是否安装,或者其它的值。有时也会用*来标注,表示由调试时决定。

⑤作为配置电路使用。这个作用跟跳线或者拨码开关类似,但是通过焊接固定上去的,这样就避免了普通用户随意修改配置。通过安装不同位置的电阻,就可以更改电路的功能或者设置地址。
0欧的电阻不但有卖,而且还有不同的规格呢,一般是按功率来分,如1/8瓦,1/4瓦等等。

如何设计一个合适的系统电源

如何设计一个合适的系统电源
对于现在一个电子系统来说,电源部分的设计也越来越重要,我想通过和大家探讨一些自己关于电源设计的心得,来个抛砖引玉,让我们在电源设计方面能够都有所深入和长进。
Q1:如何来评估一个系统的电源需求

Answer:对于一个实际的电子系统,要认真的分析它的电源需求。不仅仅是关心输入电压,输出电压和电流,还要仔细考虑总的功耗,电源实现的效率,电源部分对负载变化的瞬态响应能力,关键器件对电源波动的容忍范围以及相应的允许的电源纹波,还有散热问题等等。功耗和效率是密切相关的,效率高了,在负载功耗相同的情况下总功耗就少,对于整个系统的功率预算就非常有利了,对比LDO和开关电源,开关电源的效率要高一些。同时,评估效率不仅仅是看在满负载的时候电源电路的效率,还要关注轻负载的时候效率水平。

至于负载瞬态响应能力,对于一些高性能的CPU应用就会有严格的要求,因为当CPU突然开始运行繁重的任务时,需要的启动电流是很大的,如果电源电路响应速度不够,造成瞬间电压下降过多过低,造成CPU运行出错。

一般来说,要求的电源实际值多为标称值的+-5%,所以可以据此计算出允许的电源纹波,当然要预留余量的。

散热问题对于那些大电流电源和LDO来说比较重要,通过计算也是可以评估是否合适的。

Q2:如何选择合适的电源实现电路

Answer:根据分析系统需求得出的具体技术指标,可以来选择合适的电源实现电路了。一般对于弱电部分,包括了LDO(线性电源转换器),开关电源电容降压转换器和开关电源电感电容转换器。相比之下,LDO设计最易实现,输出纹波小,但缺点是效率有可能不高,发热量大,可提供的电流相较开关电源不大等等。而开关电源电路设计灵活,效率高,但纹波大,实现比较复杂,调试比较烦琐等等。

Q3:如何为开关电源电路选择合适的元器件和参数

Answer:很多的未使用过开关电源设计的工程师会对它产生一定的畏惧心理,比如担心开关电源的干扰问题,PCB layout问题,元器件的参数和类型选择问题等。其实只要了解了,使用一个开关电源设计还是非常方便的。

一个开关电源一般包含有开关电源控制器和输出两部分,有些控制器会将MOSFET集成到芯片中去,这样使用就更简单了,也简化了PCB设计,但是设计的灵活性就减少了一些。

开关控制器基本上就是一个闭环的反馈控制系统,所以一般都会有一个反馈输出电压的采样电路以及反馈环的控制电路。因此这部分的设计在于保证精确的采样电路,还有来控制反馈深度,因为如果反馈环响应过慢的话,对瞬态响应能力是会有很多影响的。

而输出部分设计包含了输出电容,输出电感以及MOSFET等等,这些的选择基本上就是要满足一个性能和成本的平衡,比如高的开关频率就可以使用小的电感值(意味着小的封装和便宜的成本),但是高的开关频率会增加干扰和对MOSFET的开关损耗,从而效率降低。使用低的开关频率带来的结果则是相反的。

对于输出电容的ESR和MOSFET的Rds_on参数选择也是非常关键的,小的ESR可以减小输出纹波,但是电容成本会增加,好的电容会贵嘛。开关电源控制器驱动能力也要注意,过多的MOSFET是不能被良好驱动的。

一般来说,开关电源控制器的供应商会提供具体的计算公式和使用方案供工程师借鉴的。

Q4:如何调试开关电源电路

Answer:有一些经验可以共享给大家

1: 电源电路的输出输出通过低阻值大功率电阻接到板内,这样在不焊电阻的情况下可以先做到电源电路的先调试,避开后面电路的影响。

2: 一般来说开关控制器是闭环系统,如果输出恶化的情况超过了闭环可以控制的范围,开关电源就会工作不正常,所以这种情况就需要认真检查反馈和采样电路。特别是如果采用了大ESR值的输出电容,会产生很多的电源纹波,这也会影响开关电源的工作的。

接地技术的讨论

Q1:为什么要接地?

Answer:接地技术的引入最初是为了防止电力或电子等设备遭雷击而采取的保护性措施,目的是把雷电产生的雷击电流通过避雷针引入到大地,从而起到保护建筑物的作用。同时,接地也是保护人身安全的一种有效手段,当某种原因引起的相线(如电线绝缘不良,线路老化等)和设备外壳碰触时,设备的外壳就会有危险电压产生,由此生成的故障电流就会流经PE线到大地,从而起到保护作用。随着电子通信和其它数字领域的发展,在接地系统中只考虑防雷和安全已远远不能满足要求了。比如在通信系统中,大量设备之间信号的互连要求各设备都要有一个基准‘地’作为信号的参考地。而且随着电子设备的复杂化,信号频率越来越高,因此,在接地设计中,信号之间的互扰等电磁兼容问题必须给予特别关注,否则,接地不当就会严重影响系统运行的可靠性和稳定性。最近,高速信号的信号回流技术中也引入了 “地”的概念。

Q2:接地的定义

Answer: 在现代接地概念中、对于线路工程师来说,该术语的含义通常是‘线路电压的参考点’;对于系统设计师来说,它常常是机柜或机架;对电气工程师来说,它是绿色安全地线或接到大地的意思。一个比较通用的定义是“接地是电流返回其源的低阻抗通道”。注意要求是”低阻抗”和“通路”。

Q3:常见的接地符号

Answer: PE,PGND,FG-保护地或机壳;BGND或DC-RETURN-直流-48V(+24V)电源(电池)回流;GND-工作地;DGND-数字地;AGND-模拟地;LGND-防雷保护地

Q4:合适的接地方式

Answer: 接地有多种方式,有单点接地,多点接地以及混合类型的接地。而单点接地又分为串联单点接地和并联单点接地。一般来说,单点接地用于简单电路,不同功能模块之间接地区分,以及低频(f<1MHz)电子线路。当设计高频(f>10MHz)电路时就要采用多点接地了或者多层板(完整的地平面层)。

Q5:信号回流和跨分割的介绍

Answer:对于一个电子信号来说,它需要寻找一条最低阻抗的电流回流到地的途径,所以如何处理这个信号回流就变得非常的关键。

第一,根据公式可以知道,辐射强度是和回路面积成正比的,就是说回流需要走的路径越长,形成的环越大,它对外辐射的干扰也越大,所以,PCB布板的时候要尽可能减小电源回路和信号回路面积。

第二,对于一个高速信号来说,提供有好的信号回流可以保证它的信号质量,这是因为PCB上传输线的特性阻抗一般是以地层(或电源层)为参考来计算的,如果高速线附近有连续的地平面,这样这条线的阻抗就能保持连续,如果有段线附近没有了地参考,这样阻抗就会发生变化,不连续的阻抗从而会影响到信号的完整性。所以,布线的时候要把高速线分配到靠近地平面的层,或者高速线旁边并行走一两条地线,起到屏蔽和就近提供回流的功能。

第三,为什么说布线的时候尽量不要跨电源分割,这也是因为信号跨越了不同电源层后,它的回流途径就会很长了,容易受到干扰。当然,不是严格要求不能跨越电源分割,对于低速的信号是可以的,因为产生的干扰相比信号可以不予关心。对于高速信号就要认真检查,尽量不要跨越,可以通过调整电源部分的走线。(这是针对多层板多个电源供应情况说的)

Q6:为什么要将模拟地和数字地分开,如何分开?

Answer:模拟信号和数字信号都要回流到地,因为数字信号变化速度快,从而在数字地上引起的噪声就会很大,而模拟信号是需要一个干净的地参考工作的。如果模拟地和数字地混在一起,噪声就会影响到模拟信号。

一般来说,模拟地和数字地要分开处理,然后通过细的走线连在一起,或者单点接在一起。总的思想是尽量阻隔数字地上的噪声窜到模拟地上。当然这也不是非常严格的要求模拟地和数字地必须分开,如果模拟部分附近的数字地还是很干净的话可以合在一起。

Q7:单板上的信号如何接地?

Answer:对于一般器件来说,就近接地是最好的,采用了拥有完整地平面的多层板设计后,对于一般信号的接地就非常容易了,基本原则是保证走线的连续性,减少过孔数量;靠近地平面或者电源平面,等等。

Q8:单板的接口器件如何接地?

Answer:有些单板会有对外的输入输出接口,比如串口连接器,网口RJ45连接器等等,如果对它们的接地设计得不好也会影响到正常工作,例如网口互连有误码,丢包等,并且会成为对外的电磁干扰源,把板内的噪声向外发送。一般来说会单独分割出一块独立的接口地,与信号地的连接采用细的走线连接,可以串上0欧姆或者小阻值的电阻。细的走线可以用来阻隔信号地上噪音过到接口地上来。同样的,对接口地和接口电源的滤波也要认真考虑。

Q9:带屏蔽层的电缆线的屏蔽层如何接地?

Answer:屏蔽电缆的屏蔽层都要接到单板的接口地上而不是信号地上,这是因为信号地上有各种的噪声,如果屏蔽层接到了信号地上,噪声电压会驱动共模电流沿屏蔽层向外干扰,所以设计不好的电缆线一般都是电磁干扰的最大噪声输出源。当然前提是接口地也要非常的干净。


对于现在一个电子系统来说,电源部分的设计也越来越重要,我想通过和大家探讨一些自己关于电源设计的心得,来个抛砖引玉,让我们在电源设计方面能够都有所深入和长进。
Q1:如何来评估一个系统的电源需求

Answer:对于一个实际的电子系统,要认真的分析它的电源需求。不仅仅是关心输入电压,输出电压和电流,还要仔细考虑总的功耗,电源实现的效率,电源部分对负载变化的瞬态响应能力,关键器件对电源波动的容忍范围以及相应的允许的电源纹波,还有散热问题等等。功耗和效率是密切相关的,效率高了,在负载功耗相同的情况下总功耗就少,对于整个系统的功率预算就非常有利了,对比LDO和开关电源,开关电源的效率要高一些。同时,评估效率不仅仅是看在满负载的时候电源电路的效率,还要关注轻负载的时候效率水平。

至于负载瞬态响应能力,对于一些高性能的CPU应用就会有严格的要求,因为当CPU突然开始运行繁重的任务时,需要的启动电流是很大的,如果电源电路响应速度不够,造成瞬间电压下降过多过低,造成CPU运行出错。

一般来说,要求的电源实际值多为标称值的+-5%,所以可以据此计算出允许的电源纹波,当然要预留余量的。

散热问题对于那些大电流电源和LDO来说比较重要,通过计算也是可以评估是否合适的。

Q2:如何选择合适的电源实现电路

Answer:根据分析系统需求得出的具体技术指标,可以来选择合适的电源实现电路了。一般对于弱电部分,包括了LDO(线性电源转换器),开关电源电容降压转换器和开关电源电感电容转换器。相比之下,LDO设计最易实现,输出纹波小,但缺点是效率有可能不高,发热量大,可提供的电流相较开关电源不大等等。而开关电源电路设计灵活,效率高,但纹波大,实现比较复杂,调试比较烦琐等等。

Q3:如何为开关电源电路选择合适的元器件和参数

Answer:很多的未使用过开关电源设计的工程师会对它产生一定的畏惧心理,比如担心开关电源的干扰问题,PCB layout问题,元器件的参数和类型选择问题等。其实只要了解了,使用一个开关电源设计还是非常方便的。

一个开关电源一般包含有开关电源控制器和输出两部分,有些控制器会将MOSFET集成到芯片中去,这样使用就更简单了,也简化了PCB设计,但是设计的灵活性就减少了一些。

开关控制器基本上就是一个闭环的反馈控制系统,所以一般都会有一个反馈输出电压的采样电路以及反馈环的控制电路。因此这部分的设计在于保证精确的采样电路,还有来控制反馈深度,因为如果反馈环响应过慢的话,对瞬态响应能力是会有很多影响的。

而输出部分设计包含了输出电容,输出电感以及MOSFET等等,这些的选择基本上就是要满足一个性能和成本的平衡,比如高的开关频率就可以使用小的电感值(意味着小的封装和便宜的成本),但是高的开关频率会增加干扰和对MOSFET的开关损耗,从而效率降低。使用低的开关频率带来的结果则是相反的。

对于输出电容的ESR和MOSFET的Rds_on参数选择也是非常关键的,小的ESR可以减小输出纹波,但是电容成本会增加,好的电容会贵嘛。开关电源控制器驱动能力也要注意,过多的MOSFET是不能被良好驱动的。

一般来说,开关电源控制器的供应商会提供具体的计算公式和使用方案供工程师借鉴的。

Q4:如何调试开关电源电路

Answer:有一些经验可以共享给大家

1: 电源电路的输出输出通过低阻值大功率电阻接到板内,这样在不焊电阻的情况下可以先做到电源电路的先调试,避开后面电路的影响。

2: 一般来说开关控制器是闭环系统,如果输出恶化的情况超过了闭环可以控制的范围,开关电源就会工作不正常,所以这种情况就需要认真检查反馈和采样电路。特别是如果采用了大ESR值的输出电容,会产生很多的电源纹波,这也会影响开关电源的工作的。

接地技术的讨论

Q1:为什么要接地?

Answer:接地技术的引入最初是为了防止电力或电子等设备遭雷击而采取的保护性措施,目的是把雷电产生的雷击电流通过避雷针引入到大地,从而起到保护建筑物的作用。同时,接地也是保护人身安全的一种有效手段,当某种原因引起的相线(如电线绝缘不良,线路老化等)和设备外壳碰触时,设备的外壳就会有危险电压产生,由此生成的故障电流就会流经PE线到大地,从而起到保护作用。随着电子通信和其它数字领域的发展,在接地系统中只考虑防雷和安全已远远不能满足要求了。比如在通信系统中,大量设备之间信号的互连要求各设备都要有一个基准‘地’作为信号的参考地。而且随着电子设备的复杂化,信号频率越来越高,因此,在接地设计中,信号之间的互扰等电磁兼容问题必须给予特别关注,否则,接地不当就会严重影响系统运行的可靠性和稳定性。最近,高速信号的信号回流技术中也引入了 “地”的概念。

Q2:接地的定义

Answer: 在现代接地概念中、对于线路工程师来说,该术语的含义通常是‘线路电压的参考点’;对于系统设计师来说,它常常是机柜或机架;对电气工程师来说,它是绿色安全地线或接到大地的意思。一个比较通用的定义是“接地是电流返回其源的低阻抗通道”。注意要求是”低阻抗”和“通路”。

Q3:常见的接地符号

Answer: PE,PGND,FG-保护地或机壳;BGND或DC-RETURN-直流-48V(+24V)电源(电池)回流;GND-工作地;DGND-数字地;AGND-模拟地;LGND-防雷保护地

Q4:合适的接地方式

Answer: 接地有多种方式,有单点接地,多点接地以及混合类型的接地。而单点接地又分为串联单点接地和并联单点接地。一般来说,单点接地用于简单电路,不同功能模块之间接地区分,以及低频(f<1MHz)电子线路。当设计高频(f>10MHz)电路时就要采用多点接地了或者多层板(完整的地平面层)。

Q5:信号回流和跨分割的介绍

Answer:对于一个电子信号来说,它需要寻找一条最低阻抗的电流回流到地的途径,所以如何处理这个信号回流就变得非常的关键。

第一,根据公式可以知道,辐射强度是和回路面积成正比的,就是说回流需要走的路径越长,形成的环越大,它对外辐射的干扰也越大,所以,PCB布板的时候要尽可能减小电源回路和信号回路面积。

第二,对于一个高速信号来说,提供有好的信号回流可以保证它的信号质量,这是因为PCB上传输线的特性阻抗一般是以地层(或电源层)为参考来计算的,如果高速线附近有连续的地平面,这样这条线的阻抗就能保持连续,如果有段线附近没有了地参考,这样阻抗就会发生变化,不连续的阻抗从而会影响到信号的完整性。所以,布线的时候要把高速线分配到靠近地平面的层,或者高速线旁边并行走一两条地线,起到屏蔽和就近提供回流的功能。

第三,为什么说布线的时候尽量不要跨电源分割,这也是因为信号跨越了不同电源层后,它的回流途径就会很长了,容易受到干扰。当然,不是严格要求不能跨越电源分割,对于低速的信号是可以的,因为产生的干扰相比信号可以不予关心。对于高速信号就要认真检查,尽量不要跨越,可以通过调整电源部分的走线。(这是针对多层板多个电源供应情况说的)

Q6:为什么要将模拟地和数字地分开,如何分开?

Answer:模拟信号和数字信号都要回流到地,因为数字信号变化速度快,从而在数字地上引起的噪声就会很大,而模拟信号是需要一个干净的地参考工作的。如果模拟地和数字地混在一起,噪声就会影响到模拟信号。

一般来说,模拟地和数字地要分开处理,然后通过细的走线连在一起,或者单点接在一起。总的思想是尽量阻隔数字地上的噪声窜到模拟地上。当然这也不是非常严格的要求模拟地和数字地必须分开,如果模拟部分附近的数字地还是很干净的话可以合在一起。

Q7:单板上的信号如何接地?

Answer:对于一般器件来说,就近接地是最好的,采用了拥有完整地平面的多层板设计后,对于一般信号的接地就非常容易了,基本原则是保证走线的连续性,减少过孔数量;靠近地平面或者电源平面,等等。

Q8:单板的接口器件如何接地?

Answer:有些单板会有对外的输入输出接口,比如串口连接器,网口RJ45连接器等等,如果对它们的接地设计得不好也会影响到正常工作,例如网口互连有误码,丢包等,并且会成为对外的电磁干扰源,把板内的噪声向外发送。一般来说会单独分割出一块独立的接口地,与信号地的连接采用细的走线连接,可以串上0欧姆或者小阻值的电阻。细的走线可以用来阻隔信号地上噪音过到接口地上来。同样的,对接口地和接口电源的滤波也要认真考虑。

Q9:带屏蔽层的电缆线的屏蔽层如何接地?

Answer:屏蔽电缆的屏蔽层都要接到单板的接口地上而不是信号地上,这是因为信号地上有各种的噪声,如果屏蔽层接到了信号地上,噪声电压会驱动共模电流沿屏蔽层向外干扰,所以设计不好的电缆线一般都是电磁干扰的最大噪声输出源。当然前提是接口地也要非常的干净。

嵌入式软件测试的十大秘诀(转载)

在嵌入式软件开发过程中,一般来说,花在测试和花在编码的时间比为3:1(实际上可能更多)。这个比例随着你的编程和测试水平的提高而不断下降,但不论怎样,软件测试对一般人来讲很重要。很多年前,一位开发人员为了对嵌入式有更深层次的理解,向Oracle询问了这样的一个问题:我怎么才能知道并懂得我的系统到底在干些什么呢? Oracle面对这个问题有些吃惊,因为在当时没有人这么问过,而同时代的嵌入式开发人员问的最多的大都围绕“我怎么才能使程序跑的更快”、“什么编译器最好”等肤浅的问题。所以,面对这个不同寻常却异乎成熟的问题,Oracle感到欣喜并认真回复了他:你的问题很有深度很成熟,因为只有不断地去深入理解才有可能不断地提高水平。并且Oracle为了鼓励这位执着的程序员,把10条关于嵌入式软件开发测试的秘诀告诉了他:

  1.懂得使用工具

  2.尽早发现内存问题

  3.深入理解代码优化

  4.不要让自己大海捞针

  5.重现并隔离问题

  6.以退为进

  7.确定测试的完整性

  8.提高代码质量意味着节省时间

  9.发现它,分析它,解决它

  10.利用初学者的思维

  这十条秘诀在业界广为流传,使很多人受益。本文围绕这十条秘诀展开论述。

  1.懂得使用工具

  通常嵌入式系统对可靠性的要求比较高。嵌入式系统安全性的失效可能会导致灾难性的后果,即使是非安全性系统,由于大批量生产也会导致严重的经济损失。这就要求对嵌入式系统,包括嵌入式软件进行严格的测试、确认和验证。随着越来越多的领域使用软件和微处理器控制各种嵌入式设备,对门益复杂的嵌入式软件进行快速有效的测试愈加显得重要。

  就象修车需要工具一样,好的程序员应该能够熟练运用各种软件工具。不同的工具,有不同的使用范围,有不同的功能。使用这些工具,你可以看到你的系统在干些什么,它又占用什么资源,它到底和哪些外界的东西打交道。让你郁闷好几天的问题可能通过某个工具就能轻松搞定,可惜你就是不知道。那么为什么那么多的人总是在折腾个半死之后才想到要用测试工具呢?原因很多,主要有两个。一个是害怕,另一个是惰性。害怕是因为加入测试用具或测试模块到代码需要技巧同时有可能引入新的错误,所以他们总喜欢寄希望于通过不断地修改重编译代码来消除bug,结果却无济于事。懒惰是因为他们习惯了使用printf之类的简单测试手段。下面来介绍一些嵌入式常用的测试工具。

  .源码级调试器[Source-level Debugger]

  这种调试器一般提供单步或多步调试、断点设置、内存检测、变量查看等功能,是嵌入式调试最根本有效的调试方法。比如VxWorks TornadoII提供的gdb就属于这一种。

  .简单实用的打印显示工具[printf]

  printf或其它类似的打印显示工具估计是最灵活最简单的调试工具。打印代码执行过程中的各种变量可以让你知道代码执行的情况。但是,printf对正常的代码执行干扰比较大(一般printf占用CPU比较长的时间),需要慎重使用,最好设置打印开关来控制打印。

  .ICE或JTAG调试器[In-circuit Emulator]

  ICE是用来仿真CPU核心的设备,它可以在不干扰运算器的正常运行情况下,实时的检测CPU的内部工作情况。像桌面调试软件所提供的:复杂的条件断点、先进的实时跟踪、性能分析和端口分析这些功能,它也都能提供。ICE一般都有一个比较特殊的CPU,称为外合(bond-out)CPU。这是一种被打开了封装的CPU,并且通过特殊的连接,可以访问到CPU的内部信号,而这些信号,在CPU被封装时,是没法“看到”的。当和工作站上强大的调试软件联合使用时,ICE就能提供你所能找到的最全面的调试功能。但ICE同样有一些缺点:昂贵;不能全速工作;同样,并不是所有的CPU都可以作为外合CPU的,从另一个角度说,这些外合CPU也不大可能及时的被新出的CPU所更换。JTAG(Joint Test Action Group)虽然它最初开发出来是为了监测IC和电路连接,但是这种串行接口扩展了用途,包括对调试的支持。AD公司为Blackfin设计的Visual Dsp++就支持高速的JTAG调试。

  .ROM监视器[ROM Monitor]

  ROM监控器是一小程序,驻留在嵌入系统ROM中,通过串行的或网络的连接和运行在工作站上的调试软件通信。这是一种便宜的方式,当然也是最低端的技术。它除了要求一个通信端口和少量的内存空间外,不需要其它任何专门的硬件。并提供了如下功能:下载代码、运行控制、断点、单步步进、以及观察、修改寄存器和内存。因为ROM监控器是操作软件的一部分,只有当你的应用程序运行时,它才会工作。如果你想检查CPU和应用程序的状态,你就必须停下应用程序,再次进入ROM监控器。

  .Data监视器[Data Monitor]

  这种监视器在不停止CPU运行的情况下不仅可以显示指定变量内容,还可以收集并以图形形式显示各个变量的变化过程。

  .OS监视器[Operating System Monitor]

  操作系统监视器可以显示诸如任务切换、信号量收发、中断等事件。一方面,这些监视器能够为你呈现事件之间的关系和时间联系;另一方面,还可以提供对信号量优先级反转、死锁和中断延时等问题的诊断。

  .性能分析工具[Profiler]

  可以用来测试CPU到底耗在那里。profiler工具可以让你知道系统的瓶颈在那里、CPU的使用率以及需要优化的地方。

  .内存测试工具[Memory Teseter]

  可以找到内存使用的问题所在,比如内存泄露、内存碎片、内存崩溃等问题。如果发现系统出现一些不可预知的或间歇性的问题,就应该使用内存测试工具测测看。

  .运行跟踪器[Execution Tracer]

  可以显示CPU执行了哪些函数、谁在调用、参数是什么、何时调用等情况。这种工具主要用于测试代码逻辑,可以在大量的事件中发现异常的那些。

  .覆盖工具[Coverage Tester]

  主要显示CPU具体执行了那些代码,并让你知道那些代码分支没有被执行到。这样有助于提高代码质量并消除无用代码。

  .GUI测试工具[GUI Tester]

  很多嵌入式应用带有某种形式的图形用户界面进行交互,有些系统性能测试足根掘用户输入响应时间进行的。GUI测试工具可以作为脚本工具有开发环境中运行测试用例,其功能包括对操作的记录和回放、抓取屏幕显示供以后分析和比较、设置和管理测试过程(Rational公司的robot和Mercury的Loadrunner工具是杰出的代表)。很多嵌入式设备没有GUI,但常常可以对嵌入式设备进行插装来运行GUI测试脚本,虽然这种方式可能要求对被测代码进行更改,但是节省了功能测试和回归测试的时间。

  .自制工具[Home-made tester]

  在嵌入式应用中,有时候为了特定的目的,需要自行编写一些工具来达到某种测试目的。本人曾经编写的视频流录显工具在测试视频会议数据流向和变化上帮了大忙,帮公司找到了几个隐藏很深的bug。

  2.尽早发现内存问题

  内存问题危害很大,不容易排查,主要有三种类型:内存泄露、内存碎片和内存崩溃。对于内存问题态度必须要明确,那就是早发现早“治疗”。在软件设计中,内存泄露的“名气”最大,主要由于不断分配的内存无法及时地被释放,久而久之,系统的内存耗尽。即使细心的编程老手有时后也会遭遇内存泄露问题。有测试过内存泄露的朋友估计都有深刻地体验,那就是内存泄露问题一般隐藏很深,很难通过代码阅读来发现。有些内存泄露甚至可能出现在库当中。有可能这本身是库中的bug,也有可能是因为程序员没有正确理解它们的接口说明文档造成错用。

  在很多时候,大多数的内存泄露问题无法探测,但可能表现为随机的故障。程序员们往往会把这种现象怪罪于硬件问题。如果用户对系统稳定性不是很高,那么重启系统问题也不大;但,如果用户对系统稳定很高,那么这种故障就有可能使用户对产品失去信心,同时也意味着你的项目是个失败的项目。由于内存泄露危害巨大,现在已经有许多工具来解决这个问题。这些工具通过查找没有引用或重复使用的代码块、垃圾内存收集、库跟踪等技术来发现内存泄露的问题。每个工具都有利有弊,不过总的来说,用要比不用好。总之,负责的开发人员应该去测试内存泄露的问题,做到防患于未然。

  内存碎片比内存泄露隐藏还要深。随着内存的不断分配并释放,大块内存不断分解为小块内存,从而形成碎片,久而久之,当需要申请大块内存是,有可能就会失败。如果系统内存够大,那么坚持的时间会长一些,但最终还是逃不出分配失败的厄运。在使用动态分配的系统中,内存碎片经常发生。目前,解决这个问题最效的方法就是使用工具通过显示系统中内存的使用情况来发现谁是导致内存碎片的罪魁祸首,然后改进相应的部分。

  由于动态内存管理的种种问题,在嵌入式应用中,很多公司干脆就禁用malloc/free的以绝后患。

  内存崩溃是内存使用最严重的结果,主要原因有数组访问越界、写已经释放的内存、指针计算错误、访问堆栈地址越界等等。这种内存崩溃造成系统故障是随机的,而且很难查找,目前提供用于排查的工具也很少。

  总之,如果要使用内存管理单元的话,必须要小心,并严格遵守它们的使用规则,比如谁分配谁释放。

  3.深入理解代码优化

  讲到系统稳定性,人们更多地会想到实时性和速度,因为代码效率对嵌入式系统来说太重要了。知道怎么优化代码是每个嵌入式软件开发人员必须具备的技能。就象女孩子减肥一样,起码知道她哪个地方最需要减,才能去购买减肥药或器材来减掉它。可见,代码优化的前提是找到真正需要优化的地方,然后对症下药,优化相应部分的代码。前面提到的profile(性能分析工具,一些功能齐全IDE都提供这种内置的工具)能够记录各种情况比如各个任务的CPU占用率、各个任务的优先级是否分配妥当、某个数据被拷贝了多少次、访问磁盘多少次、是否调用了网络收发的程序、测试代码是否已经关闭等等。

  但是,profile工具在分析实时系统性能方面还是有不够的地方。一方面,人们使用profile工具往往是在系统出现问题即CPU耗尽之后,而profile工具本身对CPU占用较大,所以profile对这种情况很可能不起作用。根据Heisenberg效应,任何测试手段或多或少都会改变系统运行,这个对profiler同样适用!

  总之,提高运行效率的前提是你必须要知道CPU到底干了些什么干的怎么样。

  4.不要让自己大海捞针

  大海捞针只是对调试的一种生动比喻。

  经常听到组里有人对自己正在调试的代码说shit!可以理解,因为代码不是他写的,他有足够的理由去shit bug百出的代码,只要他自己不要写出这种代码,否则有一天同组的其它人可能同样会shit他写的代码。为何会有大海捞针呢?肯定是有人把针掉到海里咯;那针为何会掉在海里呢?肯定是有人不小心或草率呗。所以当你在抱怨针那么难找的时候,你是否想过是你自己草率地丢掉的。同样,当你调试个半死的时候,你是否想过你要好好反省一下当初为了寻求捷径可能没有严格地遵守好的编码设计规范、没有检测一些假设条件或算法的正确性、没有将一些可能存在问题的代码打上记号呢?关于如何写高质量请参考林锐的《高质量c++/c编程指南》或《关于C的0x8本“经书”》。

  如果你确实已经把针掉在海里是,为了防止在找到之前刺到自己,你必须要做一些防范工作,比如戴上安全手套。同样,为了尽能地暴露和捕捉问题根源,我们可以设计比较全面的错误跟踪代码。怎么来做呢?尽可能对每个函数调用失败作出处理,尽可能检测每个参数输入输出的有效性包括指针以及检测是否过多或过少地调用某个过程。错误跟踪能够让你知道你大概把针掉在哪个位置。

  5.重现并隔离问题

  如果你不是把针掉在大海了,而是掉在草堆里,那要好办写。因为至少我们可以把草堆分成很多块,一块一块的找。对于模块独立的大型项目,使用隔离方法往往是对付那些隐藏极深bug的最后方法。如果问题的出现是间歇性的,我们有必要设法去重现它并记录使其重现的整个过程以备在下一次可以利用这些条件去重现问题。如果你确信可以使用记录的那些条件去重现问题,那么我们就可以着手去隔离问题。怎么隔离呢?我们可以用#ifdef把一些可能和问题无关的代码关闭,把系统最小化到仍能够重现问题的地步。如果还是无法定位问题所在,那么有必要打开“工具箱”了。可以试着用ICE或数据监视器去查看某个可疑变量的变化;可以使用跟踪工具获得函数调用的情况包括参数的传递;检查内存是否崩溃以及堆栈溢出的问题。

  6.以退为进

  猎人为了不使自己在森林里迷路,他常常会在树木上流下一些标记,以备自己将来有一天迷路时可以根据这些标记找到出路。对过去代码的修改进行跟踪记录对将来出现问题之后的调试很有帮助。假如有一天,你最近一次修改的程序跑了很久之后忽然死掉了,那么你这时的第一反映就是我到底改动了些什么呢,因为上次修改之前是好的。那么如何检测这次相对于上次的修改呢?没错,代码控制系统SCS或称版本控制系统VCS(Concurrent Version Control,CVS是VCS的演化版本)。将上个版本check in下来后和当前测试版本比较。比较的工具可以是SCS/VCS/CVS自带的diff工具或其它功能更强的比较工具,比如BeyondCompare和ExamDiff。通过比较,记录所有改动的代码,分析所有可能导致问题的可疑代码。

  7.确定测试的完整性

  你怎么知道你的测试有多全面呢?覆盖测试(coverage testing)可以回答这个问题。覆盖测试工具可以告诉你CPU到底执行了那些代码。好的覆盖工具通常可以告诉你大概20%到40%代码没有问题,而其余的可能存在bug。覆盖工具有不同的测试级别,用户可以根据自己的需要选择某个级别。即使你很确信你的单元测试已经很全面并且没有dead code,覆盖工具还是可以为你指出一些潜在的问题,看下面的代码:

  if (i >= 0 && (almostAlwaysZero == 0 || (last = i)))

  如果almostAlwaysZero为非0,那么last="i"赋值语句就被跳过,这可能不是你所期望的。这种问题通过覆盖工具的条件测试功能可以轻松的被发现。

  总之,覆盖测试对于提高代码质量很有帮助。

  8.提高代码质量意味着节省时间

  有研究表明软件开发的时间超过80%被用在下面几个方面:

  .调试自己的代码(单元测试)

  .调试自己和其他相关的代码(模块间测试)

  .调试整个系统(系统测试)

  更糟糕的是你可能需要花费10-200倍的时间来找一个bug,而这个bug在开始的时候可能很容易就能找到。一个小bug可能让你付出巨大的代价,即使这个bug对整个系统的性能没有太大的影响,但很可能会影响让那些你可以看得到的部分。所以我们必须要养成良好的编码和测试手段以求更高的代码质量,以便缩短调试的代码。

  9.发现它,分析它,解决它

  这世界没有万能的膏药。profile再强大也有力不从心的时候;内存监视器再好,也有无法发现的时候;覆盖工具再好用,也有不能覆盖的地方。一些隐藏很深的问题即使用尽所有工具也有可能无法查到其根源,这时我们能做的就是通过这些问题所表现出来的外在现象或一些数据输出来发现其中的规律或异常。一旦发现任何异常,一定要深入地理解并回溯其根源,直到解决为止。

  10.利用初学者的思维

  有人这样说过:“有些事情在初学者的脑子里可能有各种各样的情况,可在专家的头脑里可能就很单一”。有时候,有些简单的问题会被想的很复杂,有些简单的系统别设计的很复杂,就是由于你的“专家思维”。当你被问题难住时,关掉电脑,出去走走,把你的问题和你的朋友甚至你的小狗说说,或许他们可以给你意想不到的启发。

  总结:嵌入式调试也是一门艺术。就想其它的艺术一样,如果你想取得成功,你必须具备智慧、经验并懂得使用工具。只要我们能够很好地领悟Oracle这十条秘诀,我相信我们在嵌入式测试方面就能够取得成功。

C语言高效编程的的四招技巧(转载)

编写高效简洁的C语言代码,是许多软件工程师追求的目标。本文就工作中的一些体会和经验做相关的阐述,不对的地方请各位指教。

  第一招:以空间换时间

  计算机程序中最大的矛盾是空间和时间的矛盾,那么,从这个角度出发逆向思维来考虑程序的效率问题,我们就有了解决问题的第1招--以空间换时间。

  例如:字符串的赋值。

  方法A:通常的办法:

#define LEN 32
char string1 [LEN];
memset (string1,0,LEN);
strcpy (string1,"This is a example!!");


  方法B:

const char string2[LEN] ="This is a example!";
char * cp;
cp = string2


  使用的时候可以直接用指针来操作。

  从上面的例子可以看出,A和B的效率是不能比的。在同样的存储空间下,B直接使用指针就可以操作了,而A需要调用两个字符函数才能完成。B的缺点在于灵活性没有A好。在需要频繁更改一个字符串内容的时候,A具有更好的灵活性;如果采用方法B,则需要预存许多字符串,虽然占用了大量的内存,但是获得了程序执行的高效率。

 如果系统的实时性要求很高,内存还有一些,那我推荐你使用该招数。该招数的变招--使用宏函数而不是函数。举例如下:

  方法C:

#define bwMCDR2_ADDRESS 4
#define bsMCDR2_ADDRESS 17
int BIT_MASK(int __bf)
{
 return ((1U << (bw ## __bf)) - 1) << (bs ## __bf);
}
void SET_BITS(int __dst, int __bf, int __val)
{
 __dst = ((__dst) & ~(BIT_MASK(__bf))) | \
 (((__val) << (bs ## __bf)) & (BIT_MASK(__bf))))
}

SET_BITS(MCDR2, MCDR2_ADDRESS, RegisterNumber);


  方法D:

#define bwMCDR2_ADDRESS 4
#define bsMCDR2_ADDRESS 17
#define bmMCDR2_ADDRESS BIT_MASK(MCDR2_ADDRESS)
#define BIT_MASK(__bf) (((1U << (bw ## __bf)) - 1) << (bs ## __bf))
#define SET_BITS(__dst, __bf, __val) \
((__dst) = ((__dst) & ~(BIT_MASK(__bf))) | \
(((__val) << (bs ## __bf)) & (BIT_MASK(__bf))))

SET_BITS(MCDR2, MCDR2_ADDRESS, RegisterNumber);


  函数和宏函数的区别就在于,宏函数占用了大量的空间,而函数占用了时间。大家要知道的是,函数调用是要使用系统的栈来保存数据的,如果编译器里有栈检查选项,一般在函数的头会嵌入一些汇编语句对当前栈进行检查;同时,CPU也要在函数调用时保存和恢复当前的现场,进行压栈和弹栈操作,所以,函数调用需要一些CPU时间。而宏函数不存在这个问题。宏函数仅仅作为预先写好的代码嵌入到当前程序,不会产生函数调用,所以仅仅是占用了空间,在频繁调用同一个宏函数的时候,该现象尤其突出。

  D方法是我看到的最好的置位操作函数,是ARM公司源码的一部分,在短短的三行内实现了很多功能,几乎涵盖了所有的位操作功能。C方法是其变体,其中滋味还需大家仔细体会。

第二招:数学方法解决问题

  现在我们演绎高效C语言编写的第二招--采用数学方法来解决问题。数学是计算机之母,没有数学的依据和基础,就没有计算机的发展,所以在编写程序的时候,采用一些数学方法会对程序的执行效率有数量级的提高。举例如下,求 1~100的和。

  方法E

int I , j;
for (I = 1 I<=100; I ++)
{
 j += I;
}


  方法F

int I;
I = (100 * (1+100)) / 2


  这个例子是我印象最深的一个数学用例,是我的计算机启蒙老师考我的。当时我只有小学三年级,可惜我当时不知道用公式 N×(N+1)/ 2 来解决这个问题。方法E循环了100次才解决问题,也就是说最少用了100个赋值,100个判断,200个加法(I和j);而方法F仅仅用了1个加法,1次乘法,1次除法。效果自然不言而喻。所以,现在我在编程序的时候,更多的是动脑筋找规律,最大限度地发挥数学的威力来提高程序运行的效率。

  第三招:使用位操作

  实现高效的C语言编写的第三招——使用位操作。减少除法和取模的运算。在计算机程序中,数据的位是可以操作的最小数据单位,理论上可以用"位运算"来完成所有的运算和操作。一般的位操作是用来控制硬件的,或者做数据变换使用,但是,灵活的位操作可以有效地提高程序运行的效率。举例如下:

  方法G

int I,J;
I = 257 /8;
J = 456 % 32;


  方法H

int I,J;
I = 257 >>3;
J = 456 - (456 >> 4 << 4);

在字面上好像H比G麻烦了好多,但是,仔细查看产生的汇编代码就会明白,方法G调用了基本的取模函数和除法函数,既有函数调用,还有很多汇编代码和寄存器参与运算;而方法H则仅仅是几句相关的汇编,代码更简洁,效率更高。当然,由于编译器的不同,可能效率的差距不大,但是,以我目前遇到的MS C ,ARM C 来看,效率的差距还是不小。相关汇编代码就不在这里列举了。

  运用这招需要注意的是,因为CPU的不同而产生的问题。比如说,在PC上用这招编写的程序,并在PC上调试通过,在移植到一个16位机平台上的时候,可能会产生代码隐患。所以只有在一定技术进阶的基础下才可以使用这招。

  第四招:汇编嵌入

  高效C语言编程的必杀技,第四招——嵌入汇编。"在熟悉汇编语言的人眼里,C语言编写的程序都是垃圾"。这种说法虽然偏激了一些,但是却有它的道理。汇编语言是效率最高的计算机语言,但是,不可能靠着它来写一个操作系统吧?所以,为了获得程序的高效率,我们只好采用变通的方法 --嵌入汇编,混合编程。举例如下,将数组一赋值给数组二,要求每一字节都相符。

char string1[1024],string2[1024];


  方法I

int I;
for (I =0 I<1024;I++)
 *(string2 + I) = *(string1 + I)


  方法J

#ifdef _PC_
int I;
for (I =0 I<1024;I++)
*(string2 + I) = *(string1 + I);
#else
#ifdef _ARM_
__asm
{
 MOV R0,string1
 MOV R1,string2
 MOV R2,#0
loop:
 LDMIA R0!, [R3-R11]
 STMIA R1!, [R3-R11]
 ADD R2,R2,#8
 CMP R2, #400
 BNE loop
}
#endif


  方法I是最常见的方法,使用了1024次循环;方法J则根据平台不同做了区分,在ARM平台下,用嵌入汇编仅用128次循环就完成了同样的操作。这里有朋友会说,为什么不用标准的内存拷贝函数呢?这是因为在源数据里可能含有数据为0的字节,这样的话,标准库函数会提前结束而不会完成我们要求的操作。这个例程典型应用于LCD数据的拷贝过程。根据不同的CPU,熟练使用相应的嵌入汇编,可以大大提高程序执行的效率。

  虽然是必杀技,但是如果轻易使用会付出惨重的代价。这是因为,使用了嵌入汇编,便限制了程序的可移植性,使程序在不同平台移植的过程中,卧虎藏龙,险象环生!同时该招数也与现代软件工程的思想相违背,只有在迫不得已的情况下才可以采用。切记,切记。

星期六, 五月 19, 2007

想过吗?进程怎么样与内核比如说中断 通信呢 ?

这个问题不是我提出来的,这是我一群友提出来的。 进程间通信大家肯定能说出好多的方法,比如共享内存,socket,管道,信号两等等。可有没有想过 内核怎么样与进程间通讯呢 ?
比如说,在用户空间有一个进程要等待 I/O空间的输入,假如 外设有输入,进程就需要一定的响应,但这个消息内核如何通知用户进程呢 ? 我们知道,用户空间与内核空间的数据传送多用copy_to_user()/ copy_from_user()一类函数来实现的。我也不知道,现在转一下别人的文章

----------------------------转载于别处,谢谢这位大哥啦-------------------------------
☆─────────────────────────────────────☆
chex (继续努力) 于 (Fri Jan 2 22:15:19 2004) 提到:

不久前在几个学校bbs的linux版上闲逛,学会了不少东西,也发现了不少的问题。
在水木上就看到了有同学问linux内核态与用户态通信的问题,感觉还是蛮重要的,特别
是OS思想,所以在这里总结一下自己在这方面的经验。
首先,linux是运行在保护模式下的操作系统,所以用户态和内核态的存储区不可直
接互相访问。这就需要通过额外的手段来实现它们的通信。
其次,在linux内核态运行的代码有两种运行方式:kernel thread和tasklet。因为
tasklet是软中断触发的,所以不可睡眠,而kernel thread则在运行状态上同用户态的
进程相似,可以睡眠。
在实现通信前,我们需要了解通信一端的内核代码是什么运行方式。如果是kernel
thread,则好办得多。我们可以通过增加特殊设备的驱动程序(增加系统调用)或使用
类似setsockopt()/getsockopt()这类可以在内核中注册处理过程的方法来实现。具体可
以参见iptables或一段字符设备的驱动程序。它们实现通信的关键在于copy_to_user()/
copy_from_user()一类函数来实现用户态与内核态的内存拷贝,但此类函数会引发睡眠
,所以不能用在tasklet中。
如果内核端代码的运行方式是tasklet,则可以通过unix domain socket或netlink
socket来实现。因为unix domain socket程序在很多书中都有,所以在这里不加说明。
我们主要是来看一下如何使用netlink socket实现通信。
在linux-2.4的代码中有ipqueue这个模块,它就是用netlink socket来实现tasklet
与用户态进程通信的(源码在ip_queue.c中),但其代码较庞大,而且很多功能我们不
一定使用,所以在这里写了一段简单的代码框架,它使用netlink socket实现通信。
/* user space */
int main()
{
int sk;
struct sockaddr_nl local;
struct sockaddr_nl peer;

sk = socket(PF_NETLINK, SOCK_RAW, NETLINK_FIREWALL);

memset(&local, 0, sizeof(local));
local.nl_family = AF_NETLINK;
local.nl_pid = getpid(); /* 用户态端绑定本进程pid */
local.nl_groups = 0;
bind(sk, (struct sockaddr *)local, sizeof(local));

memset(&peer, 0, sizeof(peer));
peer.nl_family = AF_NETLINK;
peer.nl_pid = 0; /* 内核态端的netlink套接字绑定的pid是0 */
peer.nl_groups = 0;

/* netlink封包的格式必须以nlmsghdr结构变量开头,以下是最简单的实现。 */
/*
struct nlmsg
{
struct nlmsghdr hdr;
} message;
*/

memset(&message, 0, sizeof(message));
message.hdr.nlmsg_len = NLMSG_LENGTH(0);
message.hdr.nlmsg_flags = 0;
message.hdr.nlmsg_type = 0x10; /* 自定义类型 */
message.hdr.nlmsg_pid = local.nl_pid;

sendto(sk, &message, message.hdr.nlmsg_len, 0,
(struct sockaddr*)&peer, sizeof(peer));
/* 向内核态发送本地进程的信息 */
}

nlmsghdr结构体分析:
struct nlmsghdr
{
__u32 nlmsg_len; /* 封包长度(包括消息头) */
__u16 nlmsg_type; /* 消息类型(可自定义) */
__u16 nlmsg_flags; /* 附加标志 */
__u32 nlmsg_seq; /* 序列号 */
__u32 nlmsg_pid; /* 发送进程ID */
};
如此便在用户态创建了一个netlink套接字。发送和接受数据的函数分别为sendto()
和recvfrom()。

内核态创建netlink套接字的过程:
struct sock *nfnl = NULL;
……
{
……
nfnl = netlink_kernel_create(NETLINK_FIREWALL, netlink_receive);
……
}

static DECLARE_MUTEX(sqnl_sem); /* 定义锁 */
/* 用来接收用户态进程传来数据的函数。 */
static void netlink_receive(struct sock *sk, int len)
{
do
{
struct sk_buff *skb;
if(down_trylock(&sqnl_sem))
return;
while((skb = skb_dequeue(&sk->receive_queue)) != NULL)
{
{
struct nlmsghdr *nlh;

if(skb->len >= sizeof(struct nlmsghdr))
{
nlh = (struct nlmsghdr*)skb->data;
if(nlh->nlmsg_len >= sizeof(struct nlmsghdr)
&& skb->len >= nlh->nlmsg_len)
{
……
/* 保存相应的pid */
……
}
}
}
kfree_skb(skb);
}
up(&sqnl_sem);
}while(nfnl && nfnl->receive_queue.qlen);
}
这里sqnl_sem锁的作用大家来讨论一下吧,还有,这里最后的while,又对nfnl的接收队列做了判断,不知各位的看法如何?(因为我的想法还不成熟,不好意思说出来)

内核态发送消息的代码框架:
struct message
{
char buf[16]; /* 要传送的信息 */
};

……
{
unsigned char *old_tial;
int size;
struct sk_buff *skb;
struct nlmsghdr *nlh;
struct message *pmsg;

/* 分配一个数据长度为(消息长度+消息头)并4字节对齐后的skb */
size = NLMSG_SPACE(sizeof(message));
skb = alloc_skb(size,GFP_ATOMIC);
old_tail = skb->tail; /* 记录当前octet尾部位置 */

nlh = NLMSG_PUT(skb, 0, 0, 0x11, size – sizeof(*nlh));
pmsg = NLMSG_DATA(nlh);
strcpy(pmsg->buf,”MESSAGE”);
nlh->nlmsg_len = skb->tail – old_tail;

/* 这里需要设置,因为alloc_skb宏并不会为新开辟的缓存清0 */
NETLINK_CB(skb).dst_groups = 0;
return netlink_unicast(nfnl, skb, userpid, MSG_DONTWAIT);

nlmsg_failure:
if(skb)
{
kfree_skb(skb);
}
……
return -1;
}

以上代码(运行在i386计算机上)用到了不少文件linux/netlink.h中定义的宏,大
家可以看该文件参考一下,我感觉这些宏很好用,所以在这里使用了它们。以上还有很多
值得讨论的地方,希望大家不要客气:)

----------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------

不知道他的想法对不对,大家假如有好的办法可以留言给我,或者邮件通知我 gaominggm#gmail.com 谢谢啊 !!!!!!

星期四, 五月 17, 2007

面试总结

面使官你好,谈嵌入式开发,嵌入式开发的特点就是 硬件与软件结合的比较的紧密。硬件的不通,必然会引起软件的不同 我比较熟悉ARM处理器,首先 ARM处理器是 精简指令集的处理器。ARM处理器有 7个处理器模式,用户,管理,系统,中断,快中断,异常还有未定义模式,其中,处理器有 31个通用寄存器,6个状态寄存器。在这些寄存器中,不同的处理器模式下,可以使用的处理器是不同的。其中 CPSR是状态寄存器,还有 SPSR辅助状态寄存器,用来临时保存 CPSR。其总,处理器的模式还有 中断,快中断的使能都是通过 CPSR里面的标志位来实现的。还有一些 关键的寄存器,在每个处理器模式下,都有自己的 R13(堆栈寄存器)和R14(链接寄存器,保存返回地址),所以,在bootloader 的开发中,必须要初始化各个模式下的 R13堆栈寄存器。还有,ARM处理器除了 Load/Store指令能访问存储器外,其余指令都是通过寄存器来操作的。还有,更改程序的流程一般可以用 跳转指令 B,不过,跳转指令最大的跳转范围是 前后32M,还有一种实现程序跳转的方法是 直接更改 当前 PC (R15)程序计数器的值,这样,程序就可以实现地址32位的跳转啦 !ARM指令还有一些 多寄存器加载指令,这些指令一般用过 保护/恢复 上下文。(上下文,就是当前的 各个寄存器的值)。 到这里,我就 堵车啦 !!!!!!

N次面试的总结+最近学习的总结

大家认为最厉害的面试官会问你什么问题吗 ?
我认为,最好的一问一答的,呵呵,这样好多问题他也不知道,所以我也就可以逃脱过去,还有一些问题自己也可以侥幸的回答。最厉害的面试官是什么也不需要问的,他知会让你去说,让你去把你已经记在脑子里(而不一定是掌握)的东西说给他听!!!通过你讲,他就知道你对 这方面的知识的了解程度了!!!
我认为是这样的,对于向我这样的初学者,ARM+Linux都不怎么熟悉,要你好好的把你认为的嵌入式的理解说出来,的确,对一个高手来说,让他讲讲嵌入式开发的经验,你给他一天的时间他也讲不完,这就不像我这样,没有经验,功底不深厚的人说几句就堵车的样子。我认为这样的面试官是最厉害的。
不过,上有政策,下有对策。那就是在面试之前好好的准备,假如让我说的话,我应该怎么回答他,以致于让他不能插嘴,只有我一人能好好的侃侃而谈!!这样才能显得出我们的博学!!!是啊,这样的方法很好,但有的时候,不知道自己是在怕什么,不敢去想!!是胆小。是XX恐惧者!!
为了下次不会出现面试 堵车 的 现象,下次blog内容就是关于面试的主要谈论的内容 !!!

星期日, 五月 13, 2007

随想

呵呵,心里总是觉得有好多的话要说,有好多要写的东西,可是,每当打开电脑,就不知道该写一些什么,这我想起上小学的时候,老师让我们写作文的时候的感觉!! 哈哈!!!

这几天也没有好好的看书,说是不断的学习,可现在没有当初的那一股精神气了,写此篇文章,就当是自勉啦!!
假如一个人有了 恒心,爱心,耐心,细心,这个肯定就是 神了,我想这样的人,只要他想,没有他办不到的事情。 他应该是我努力的方向。的确,好好学习,好好的看书,人生的目标总是可是达到的。不要去怪天怪地。内因是决定事物发掌的方向。有一些问题,明明自己知道答案放在什么地方,而自己总是懒惰的找,难道自己为了自己达到人生的目标,能 不劳而获么? 这肯定是不能的,偶一天,看一好友的资料这样写
“每本用来解惑的书都值得珍惜。明知道答案在那里却不去努力,是一种悲哀。”
的确是这样的,书中有好多工作的答案,而自己却没有去好好寻找。书中自有颜如玉,书中自有黄金屋,自己不去寻找,生活中的不如意也就不能去怪罪任何人了。佛教的根基就是“因果报应”,有因必有果,有果必有因,果不虚处,因不白出。
自己知道什么样的答案,自己是清楚的,希望能时刻提醒自己,不能在虚度光阴了。上天在某些方面是很不公平的,但,对于时间,每个人都是相同的。在相同的时间呢,看看谁能做出更大的成就,谁才是真正的智者!
一个人,假如有强烈的使命感,责任感,他一定会能有所成就的!!
谁想做一个 平平凡凡的人 ?谁想做普通的人呢? 我想,我现在不会在上面留下自己的名字的!

星期二, 五月 08, 2007

最惨的一次面试

今天上午去一家XX公司去面试,说好是11 点面试。本着我求人的态度,我10点半就到公司了,到了公司,前台一女让我填了一个表,好麻烦的一张表,要填 小学,初中,大学,父母,身份证号,有无疾病.....比档案馆的还要全。一看我就晕,我就草草的写了一些必须填写的,比如性别啊,哈哈。 等填写完了,前台就让我一边等着去了。其中,在等的时候,就听见旁边隔壁屋子里面有 面试官和面试的人的谈话,真让我紧张,足足让我等了半个小时。突然,不知道从哪冒出一女,让我去面试,此女中年(有一点黑),要面试我。 我一瞅,此女非技术也。没办法,就跟着进去了。 在谈话中,此女啥也不懂,问的问题都很傻,甚么 EEROM 怎么读写? 还好,他知道 EEROM,可怎么读写是硬件的事情,他问的都是不着边的问题。 这个面试,我太激动了,让我本来计划好的面试计划全打乱了,快12点了,此女可能饿了,好多电话不停,,我只能自己着最后的总结,真不好!!!!!她不懂还是装很懂 !最怕这样的人。我到真希望能碰到技术高手,尽管面试不顺利,高手也能提醒你多注意哪些。假如碰见此女这样的,不懂装懂的,能把你搞晕!!!

星期五, 五月 04, 2007

最近找不着北啦!!

这几天,不知道是怎么了,突然放松警惕了。没有以前的奋斗的那股精神了。
难道现在不是 破釜沉舟 吗?
现在应该是了。