http://antkillerfarm.github.io/
开篇的话
自从改行做起了驱动软件工程师,好多硬件的问题已经不再像当初那样,可以忽略不计了。于是就有了以下的心得。
0欧电阻的作用
在硬件原理图,特别是硬件草案的原理图中,常可看到0欧的电阻。0欧的电阻在效果上当然等同于导线,辛辛苦苦把它引出来焊上,究竟有何用处呢?硬件的同事告诉我,他们一般只在某些新添加的电路上使用这东西。一旦由于某些原因需要去掉新添加的电路的话,只要用电烙铁把电阻取下来就可以了,而不用再造一批测试版。
空指针
空指针的概念,本来主要是个软件概念。上学的时候,教C语言的老师,就反复强调要检查空指针。
课本上给出的标准做法是:
1)声明一个指针变量,并初始化为NULL。
2)在程序执行过程中,指针被赋值为一个有某种含义的非空值。
3)使用该指针前,检查其是否是空指针。
这里就有疑问了。C语言中所谓的指针,保存的不过是个地址值。请看下面的例子:
int a[10];
int *p = a;
在这里p表示数组a的首地址,p+1表示a[1]的地址,那么p-1呢?在通常情况下,这也是个有意义的地址,只不过我们不知道它属于哪个变量罢了。所以课本中的做法的一个隐含的前提就是,NULL不属于任何变量。否则的话,对于以NULL开始的变量来说,检查空指针显然就毫无意义了。
对NULL的特殊性还有所怀疑的同学,可以试试往p-1中写数据和往NULL中写数据,看看在执行的时候,现象有什么不同。
从硬件的角度来说,32位的处理器有32位的地址总线,因此理论上说它的地址空间也是32位的。但是并非32位的地址都是有意义的。在一些嵌入式设备上,可能外设会占掉一部分地址空间,内存会占掉另一部分地址空间,其余的都是未定义的地址空间。向这些未定义的地址读写数据,会产生错误,通常的表现就是产生了一个异常或者中断。
在PC上,由于外设和内存有各自独立的地址空间,再加上虚拟内存的关系,这种未定义的地址空间是没有了,但是NULL开始的一段地址空间,会被定义为保护段,对其的读写同样会引发异常或者中断。(关于PC的结论,仅针对一般的用户态程序,内核态程序不适用。)
因此往NULL中读写数据的BUG,通常是比较好解决的。而往p-1中写数据的BUG,没有相当的技巧或工具的话,是很难解决的。
IRQ与FIQ的区别
IRQ(Interrupt Request):指中断模式。
FIQ(Fast Interrupt Request):指快速中断模式。
是ARM处理器的两种不同编程模式(ARM有7种处理模式)。
1、对FIQ你必须进快处理中断请求,并离开这个模式。
2、IRQ可以被FIQ所中断,但FIQ不能被IRQ所中断,在处理FIQ时必须要关闭中断。
3、FIQ的优先级比IRQ高。
4、FIQ模式下,比IRQ模式多了几个独立的寄存器。
不要小看这几个寄存器,ARM在编译的时候,如果你FIQ中断处理程序足够用这几个独立的寄存器来运作,它就不会进行通用寄存器的压栈,这样也省了一些时间。
5、FIQ的中断向量地址在0x0000001C,而IRQ的在0x00000018。(也有的在FFFF001C以及FFFF0018)
写过完整汇编系统的都比较明白这点的差别,18只能放一条指令,为了不与1C处的FIQ冲突,这个地方只能跳转,而FIQ不一样,1C以后没有任何中断向量表了,这样可以直接在1C处放FIQ的中断处理程序,由于跳转的范围限制,至少少了一条跳转指令。
6、IRQ和FIQ的响应延迟有区别
IRQ的响应并不及时,从Verilog仿真来看,IRQ会延迟几个指令周期才跳转到中断向量处,看起来像是在等预取的指令执行完。FIQ的响应不清楚,也许比IRQ快。
RISC vs. CISC
记得当初在学校里,学习“计算机组成原理”时,碰到了这两个概念。课本上的准确提法记得不确切了,但大致是这个样的(文献A):
http://blog.ednchina.com/playlinus/39520/message.aspx
本来没有什么,课本上写些什么,记住就行了。直到遇到这篇文章(文献B):
文章中的“RISC OR CISC已经不再重要”这句话引起了我的注意和思考。
一直以来大部分课本上的观点是这样的:RISC由于速度快,必将取代CISC,而之所以没取代,主要是由于现在的大部分软件只能运行在X86体系上,也就是说是由于非技术的市场原因导致的。
市场原因当然不在我这篇文章的考量范畴,但“RISC比CISC快”这个结论却值得打个问号。
课本中给出的解释是:CISC由于指令复杂,所以需要将每条指令分解成微指令,才能执行,因此指令的CPI(Cycles Per Instruction)要比RISC高,所以就慢。RISC尽管完成同样的功能需要更多的指令,但根据80/20的原则,总的来说还是要比CISC快。
应该说这个结论,在上个世纪90年代中期以前,的确是颇有道理的。但主板倍频技术的出现,让这个问题有了新的变化。在早期的X86计算机中,CPU和内存工作在同样的频率下,也就是说CPU和内存一样快。而使用倍频技术后,CPU频率和内存频率之间就产生了差距。这种差距到后期,竟然几乎相差了一个数量级,这个时候CPI就不再是决定CISC和RISC快慢的决定因素了。CISC由于指令密度高,在某些场合甚至比RISC快也就不足为奇了。
事实上,正如文献B中所示的,现在商用的CPU已经无法再用文献A中的定义来分类了,因为他们都借鉴了对方的某些优点。
1.提高指令密度。ARM按照传统来说是RISC,但它引入了Thumb指令来提高指令密度,因此它的指令集不再是传统RISC的定长指令集。
2.减少CPI。Intel的X86 CPU最初只有一个指令解码器,而现在为了处理最常用的20%的简单指令,它引入了简单指令解码器的概念,再加上指令流水线的引入,它在CPI上的表现与传统的RISC已经没有什么太大的差别了。
顺便说一句,Linux在多核机器上引入了“自旋锁”的概念。自旋锁的实现,说白了就是一种有条件的死循环,从表面看,死循环空占CPU,似乎是种很低效的方案,但由于CPU和其他设备之间速度的巨大差异,有时候这种方案反而是最快的方案。道理和上面的RISC vs. CISC是类似的。
总之,每个时代限制系统速度的瓶颈不同,因而完全有可能昨天的结论和今天的结论完全相反。
pin 1
一般的排线为了能够方便的识别pin 1,通常会在pin 1处标一个小三角,并且pin 1线的颜色也与其他的线不同。
单火线
最近研究智能家居,提到了单火线的概念,现简要描述如下:
这是一个接入电网的灯泡的原理图,图中的两根线,上面的是火线,下面的是零线。实际生活中的那些没有开关的插座灯泡就是以这样的方式接入电网的。
这是普通的开关灯泡的原理图。
这是单火线家居灯泡的原理图。从拓扑结构上来说,这个图和上一个图的结构是一样的。之所以画的时候故意弯曲了一下,是想表明一个事实:开关和灯泡之间有一定的距离。实际上对于一般的家居灯泡来说,零线、火线、开关和灯泡之间的线都是建筑商在建筑施工时,布设在墙体内部的。
那么问题就来了。由于开关和灯泡是串联的,当我们将传统的机械开关替换为智能开关的时候,由于开关本身没有和零线直接相连,因此当灯泡处于关闭状态的时候,开关本身也将无电可用。
解决的办法:
为开关再接一根线。
这就是所谓的零火线开关。但这样做的问题是,需要重新在墙体内走线布线,有比较大的施工量,对于已经入住的房屋来说,并不是太现实。这也是阻碍智能家居走进家庭的一个重要的技术问题。
单火线取电
通过加装电容等储电元件,可以给开关提供断电时的能源。但由于开关和灯泡是串联的,当灯泡本身的功耗较小时,储电元件的微小电流不仅会维持开关的工作,亦会点亮灯泡,造成灯泡在关闭状态下仍有微弱的光亮,即俗称的“鬼火”现象。这个在低功率的LED灯上,表现的十分明显。
ISP与IAP
ISP(In-System Programming)在系统可编程,指电路板上的空白器件可以编程写入最终用户代码,而不需要从电路板上取下器件,已经编程的器件也可以用ISP方式擦除或再编程。
IAP(In-Application Programming)指MCU可以在系统中获取新代码并对自己重新编程,即可用程序来改变程序。
与ISP、IAP相对应的是早期单片机所使用的存储器烧写器,该方式需要从电路板取下存储芯片,安装到烧写器上烧写之后,再放回原电路板。这种传统的方式目前已经用的非常少了。
上拉电阻和下拉电阻
上拉就是将不确定的信号通过一个电阻钳位在高电平,电阻同时起限流作用。下拉同理,也是将不确定的信号通过一个电阻钳位在低电平。
上拉是对器件输入电流,下拉是输出电流;强弱只是上拉电阻的阻值不同,没有什么严格区分;对于非集电极(或漏极)开路输出型电路(如普通门电路)提供电流和电压的能力是有限的,上拉电阻的功能主要是为集电极开路输出型电路输出电流通道。
BGA & QFP
BGA封装,就是那种引脚都在芯片背面的封装。QFP封装,即四侧引脚扁平封装。同样面积情况下,显然占据一个面的引脚数,要超过仅占据四个边的引脚数。
nor flash & nand flash
flash按照内部存储结构不同,分为两种:nor flash和nand flash。
NorFLASH使用方便,易于连接,可以在芯片上直接运行代码,稳定性出色,传输速率高,在小容量时有很高的性价比,这使其很适合应于嵌入式系统中作为FLASH ROM。
在通信方式上Nor Flash分为两种类型:CFI Flash和SPI Flash。
NandFLASH强调更高的性能,更低的成本,更小的体积,更长的使用寿命。这使NandFLASH很擅于存储纯资料或数据等,在嵌入式系统中用来支持文件系统。NandFLASH存在坏块问题。