版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、嵌入式软件开发人员,硬件常识底层的驱动或内核开发人员通常要跟硬件紧密的配合,协同完成工作.硬件电路的设计很大程度上决定驱动代码的代码的编写.一个熟练的底层开发人员具备硬件开发知识本节内容.l 硬件开发流程l 硬件识图l 软件控制硬件方法l 嵌入式C语言硬件开发知识l 大致清楚硬件的设计和生产流程.l 清楚自已工作中常用的硬件器件的工作原理.l 要有看懂硬件原理图的能力.主要涉及影响到编程的关键的连线和管脚的一定要看懂.l 要看懂硬件(主要是能编程控制的集成电路,简称IC)的编程资料,一般是称为DataSheet的PDF文档.主要各个寄存器的设置,和常见任务的处理流程软件相关能力l 要知道如何用
2、编程语言(主要是C,和少量的汇编)去控制硬件.l 还要熟悉底层软件与操作系统的接口.n 象同一款硬件,原始的控制代码是基本上一样的,但是各个操作系统对驱动与OS的接口,完全不一样.Windows系列的驱动接口远比Linux复杂得多.各个操作系统也提供了不同底层函数接口用于开发,这些都需要熟练掌握的.l 具有调试底层软件的能力,除了常用的软件调试手段,(如单步DEBUG,查看输出信息.)有时可能需要动用软件,和硬件检测设备来调试n 如网络调试,可能需要抓包软件,基于硬件的流量测试仪n 基于硬件的电路的仪器,如万用电表,显波器和逻辑分析仪n 基于无线的设备,可能需要无线信号发生器或基站模拟设备在底
3、层软件开发领域,还有一些非标准CPU的分支开发领域,由于采用接近于CPU的复杂结构,因此必须用的编程语言去开发,但又不是普通的gcc那样的开发环境.而是自己独立的开发环境.很多嵌入式工程师需要常握其中一种工具l 常用数据处理,如音频,加密,视频影像处理的DSP,都会有自已独立的开发环境,有的是接近汇编级的语法代码,更高级是类似于C的编程语言.常见的DSP开发环境有TI的CCP.l 在网络流量很大的地方,如核心路由器,大型的防火墙,网关,等,这一些设备有时用软件已经无法处理.往往采用基于网络处理器的的方案,网络处理器会在硬件直接处理网络包,这些网络处理器也有独立的开发环境用于开发.如Intel的
4、IXP系列.l FPGA,CPLD (VHDL)用类似于Basic 或C语言的开发语言去设计硬件,如MaxPlus IIl labView 虚拟仪器.硬件产品设计流程 与软件不同,一个硬件产品的从最基本的器件到最终产品的出产,是一个全球化高度合作的结果.牵涉一个完整的产业链的方方面面.因此必须需要高度工程化的管理和生产技术.否则不可能生产出合格产品.以一台手机生产而言.它的技术标准和研发可能是在欧美的大公司或大学的研究机制进行.如Nokia和爱立信,高通等来进行研发的.当技术成熟后,可能在美国的IC设计公司(如TI)设计出可以满足实际产品的集成电路,这个集成电路的生产,出厂测试等流程可能是在台
5、湾新竹的台积电,联电的IC生产工厂代工.单独的IC并不能形成产品,必须要焊接在电路板上,和其它电件组成完整的电路.这是一个风险很高的设计过程.以前要由最终的产商完成这样的工作,这样会花费很长的时间和资金,并且有可能失败.现在流行的趋势是由专业的设计公司负责完成硬件电路和底层软件的设计,甚至是应用程序的开发,这大大降低了生产厂家的门槛.象手机设计里最有名的是MTK(联发科技),它提供底层的IC到硬件电路方案,+软件方案的全套设计.这样很多小厂也能直接生产手机.号称是黑手机之父,这几年的大量的手机上市,它功不可没.也造就它成为台湾股市的股王.在低端MP3,MP4领域里,采用相同策略是位于珠海的炬力
6、,它也推出MP3和MP4播放器从IC到硬件设计方案,软件的全套设计方案.造成现在MP3,MP4市场大规模爆发.如果是从元器件开始设计一个电子产品.第一阶段是硬件工程师要根据参考方案和文档,设计出一个硬件原理图来.主要用来验证电路产否能正常正确,确定硬件的连线等工作.类似于产品硬件设计模型.这一项工作一般是由一个公司最有经验的工程师来完成.原理图都是一个逻辑表示,比如元器件用示意图表示,连线也不会跟最终产品的走线一模一样.IC是高度集成的精密器件,不可能象电气设备一样,直接拉线就行.通常会在一个缚有一层导电金属层的绝缘板用化学方法”刻”一根一根的导线.然后再焊接上去.这种板就称为PCB ( Pr
7、inter Circuit Board).这种方法有很多优点,节约空间,防止干扰,焊接点小,并且牢固.集成度高,因此现代的电子元件互联完全采用PCB板来制作.因此硬件设计第二阶段就要是把原理图设计成供生产的PCB图.类似于建筑施工图,里面的设计布局将会跟实际产品开发一规一模.PCB也是取决于设计经险,但很多是重复劳动,在很多小的公司往往采用外包的方式让专业的PCB公司来代为设计,深圳就有大量公司或工作室来代人完成PCB设计.原理图设计,和PCB设计都需要专用软件来完成.现在有设计软件从几十W到几W的软件都是,象常用的Prototel ,PowerLogic/PowerPCB是比较流行的硬件设计
8、.可以完成二阶段设计.高端设计软件有Cadence.当完成PCB设计后,一方面准备制作PCB板了.由于PCB的制作设备非常昂贵.一般是由专门PCB生产厂家来代工.深圳是中国以及世界上最集中PCB产业地,拥有大量PCB制作厂家.另一方面由PCB图导出BOM(元器件清单)交由采购部门进行采购.现代的IC的管脚已经越来越复杂,采用手工焊接效率低,失败高,往往需要专门焊接厂进行全自动的焊接.深圳拥有大量焊接工厂.往往是PCB制版厂业务之一.当一个产品完成后,就要设计吸引人的产品外壳,这称为结构设计.比较简单的是用金属冲压件.如果电脑机箱,机柜之类.优点设计成本低,可以快速实现.缺点就是一般只能是带直角
9、的设计.外形过于简单. 现在大部分电子产品采用塑料外壳.优点可以做出非常复杂的外形.并且可以采用不同材质进行组合.缺点是设计复杂,并且要用设计专用模具来生产.现在结构设计软件有 普遍采用Pro/E 或UG来进行设计.也有人使用AutoCAD来设计.现在结构设计一般也是外包给专业的设计公司进行设计.很多产商为了节约成本,往往采用模具厂预先做的好模具,这个称为”公模”.欧美市场对环保有极为严格的要求,如果产品要销往欧美市场,往往需要使用无铅的焊锡,油漆.电磁辐射也有强制要求.以有其它的准入门槛.如欧盟的CE认证,美国的UL认证,FCC认证等,这一些都是强制标准,必须先在先由认证的代理机构认证后.才
10、能在上述市场销售.这是必须一个环节.电路图的识图能力常见电路图有三大类框图(BLOCK DIAGRAM),原理图和PCB图,时序图框图用于描述系统结构,一般用于文档描述.原理图用于系统原理设计.同时进行底层软件编程时往往需要多次查阅原理图的设计.PCB图用于实际生产.软件编程一般不需要查看PCB图. 底层软件人员往往需要了解是时序图(Timing),用于反映多个信号源(或管脚)之间信号的相互关系。因为一个硬件完成一项工作必须是多个管脚协同工作。而且往往有时间顺序上的要求。而时序图就是反应这种时间上的信号之间相互关系的图形,大量于IC的设计文档,在实例运行中,往往也可以用显波器之类设备测量出这种
11、波形关系。用于协助软件人员调试错误。S3C2440的原理框图QQ2440部分原理图一个S3C2410开发板的PCB图信号时序图(Timing) SPI总线时序常用时序图 NAND Flash 控制时序图,有规则的波形(HCLK)一般用于表示时钟信号,用于不同信号计时。上例中,表示在第二个时钟周期时,CLE/ALE的必须由低平切换为高电平。在第三个时钟周 期,new由高电平变为低电平。用双线表示波形,即DATA,表示高低电平不确定,必须取决于当时应用的情况。比如在这个例子,DATA在有效的时钟周期,传输是不同命令或地址。 一个复杂的时序图内存控制器的时序图 软件控制硬件方法作为一个嵌入式软件开发
12、人员,必须熟悉如何控制硬件.首先从技术要确定项目开发采用哪种CPU.这取决项目人员技术背景,产品以前经验以技术特点等.一般公司尽可能采用同一种CPU来开发不同产品.这样可以最大可能节约成本,并且技术风险比较小.当确定的CPU后,研发人员就要研究的CPU相关文件.指令集和测试程序.这一些都要在项目开始前完成.硬件IC的手机通常是PDF格式的.称为DataSheet.CPU的datasheet是相当于一本厚厚的技术词典.如S3C2440的datasheet 有596页.如果要控制比较复杂的外部设备,通常还要去阅读相应的手册.因此在开发前,最好尽可能阅读尽可能多的手册. 以S3C2440 CPU为例
13、.首先要了解一下CPU的框图,了解这一款CPU的大致部件.从这个框图可以看到,这一款CPU具备的基本硬件包括内存,LCD,串行端口.电源等.这几个也是嵌入式系统中最常见到的几项装置.另外这个CPU还提供了许多的GPIO(General Purpose I/O)管脚,让设计者可以根据自已的需求来控制这一些外围设备,这是一个很典型的一种做法.如果这些外围还是不够的话,就要自已加控控制芯片,拉到地址线(address line)及总线(bus line)上,通过这些线来控制外围,像是SDRAM或是Flash 就是通过地址线与总线来存取数据.有三个概念要分清楚,存储器,I/O端口,寄存器.寄存器是指C
14、PU和外设内部的存储单元,数量有限,但速度快,分通用寄存器和特殊功能寄存器(比如pc,sp等)。不同CPU寄存器宽度是不一样的.8位单片机表示地址线和数据为8位大小.寄存器宽度也是8位,在C程序中正好可以用一个char 数据类型来操作.主流32位CPU的寄存器就是32位宽度.正好用一个32位,在程序中可以用一个unsigned int 来操作.CPU的寄存器或地址位的宽度称为WORD(字)通常说的存储器都是独立于CPU之外的,比如内存,硬盘,光盘等.CPU本身几乎每一种外设都是通过读写设备上的寄存器来进行操作的。外设寄存器也称为“I/O端口”,通常包括:控制寄存器、状态寄存器和数据寄存器三大类
15、,而且一个外设的寄存器通常被连续地编址。CPU对外设IO端口物理地址的编址方式 有两种:一种是I/O映射方式(I/Omapped),另一种是存储空间映射方式(Memorymapped)。而具体采用哪一种则取决于CPU的体系结构。有些体系结构的CPU(如,PowerPC、m68k等)通常只实现一个物理地址空间(RAM)。在这种情况下,外设 I/O端口的物理地址就被映射到CPU的单一物理地址空间中,而成为存储空间的一部分。此时,CPU可以象访问一个内存单元那样访问外设I/O端口,而不需要 设立专门的外设I/O指令。这就是所谓的“存储空间映射方式”(Memorymapped)。ARM体系的CPU均采
16、用这一模式.而另外一些体系结构的CPU(典型地如X86)则为外设专门实现了一个单独地地址空间,称为“I/O地址空间”或者“I/O端口空间”。这是一个 与CPU的RAM物理地址空间不同的地址空间,所有外设的I/O端口均在这一空间中进行编址。CPU通过设立专门的I/O指令(如X86的IN和OUT指 令)来访问这一空间中的地址单元(也即 I/O端口)。这就是所谓的“I/O映射方式”(I/Omapped)。与RAM物理地址空间相比,I/O地址空间通常都比较小,如x86 CPU的I/O空间就只有64KB(00xffff)。这是“I/O映射方式”的一个主要缺点。而且必须要专门的汇编语言才能处理.Linux
17、 即在X86运行,也在ARM之类运行.为了简化操作,Linux在所以CPU上都采用I/O端口概念.如果是象ARM这样内存映射.也被模拟成端口.在非操作系统模式下.一般直接采用内存取读模式.在ARM下,所有外设的寄存器都被映射到一个4G空间.并且是有固定的映射地址.(注意要与操作系统下的映射2G地址空间分开,那是操作系统给每个进程模拟的空间,I/O地址实际映射物理地址空间)以下是在S3C 2440的Nand/Nor 在设备空间映射地址空间所有S3C2440寄存器地址映射表写在手册 55页(1-32)如下例就是内存控制器相关的寄存器地址设置一般的PC机和ARM板都带有外接电池供电的RTC(REAL
18、 TIME CLOCK实时时钟)芯片,即便是切断的外接电源,RTC电路记录的时间也会按真实时间流逝而做相应变化.假设现在要使用RTC电路.即从RTC电路存储的时间信息读取出来.首先根据地址表找出RTC电路寄存器相关地址.(S3C2440芯片手册P66)其中存储年月日小时分钟,秒的的寄存器分别是 BCDSEC,BCDMIN,BCDHOUR,BCDDATE,BCDDAY,BCDMON,BCDYEAR.地址从0x570000770x5700008B 地址.在C语言中为,方便程序编写,往往把寄存器定义为宏,这样当CPU微调的寄存器定义,程序不需要重写.参见2440addr.h的定义/ RTC#ifde
19、f _BIG_ENDIAN#define rRTCCON (*(volatile unsigned char *)0x57000043)/RTC control#define rTICNT (*(volatile unsigned char *)0x57000047)/Tick time count#define rRTCALM (*(volatile unsigned char *)0x57000053)/RTC alarm control#define rALMSEC (*(volatile unsigned char *)0x57000057)/Alarm second#define r
20、ALMMIN (*(volatile unsigned char *)0x5700005b)/Alarm minute#define rALMHOUR (*(volatile unsigned char *)0x5700005f)/Alarm Hour#define rALMDATE (*(volatile unsigned char *)0x57000063)/Alarm date /edited by junon#define rALMMON (*(volatile unsigned char *)0x57000067)/Alarm month#define rALMYEAR (*(vol
21、atile unsigned char *)0x5700006b)/Alarm year#define rRTCRST (*(volatile unsigned char *)0x5700006f)/RTC round reset#define rBCDSEC (*(volatile unsigned char *)0x57000073)/BCD second#define rBCDMIN (*(volatile unsigned char *)0x57000077)/BCD minute#define rBCDHOUR (*(volatile unsigned char *)0x570000
22、7b)/BCD hour#define rBCDDATE (*(volatile unsigned char *)0x5700007f)/BCD date /edited by junon#define rBCDDAY (*(volatile unsigned char *)0x57000083)/BCD day /edited by junon#define rBCDMON (*(volatile unsigned char *)0x57000087)/BCD month#define rBCDYEAR (*(volatile unsigned char *)0x5700008b)/BCD
23、year#else /Little Endian#define rRTCCON (*(volatile unsigned char *)0x57000040)/RTC control#define rTICNT (*(volatile unsigned char *)0x57000044)/Tick time count#define rRTCALM (*(volatile unsigned char *)0x57000050)/RTC alarm control#define rALMSEC (*(volatile unsigned char *)0x57000054)/Alarm seco
24、nd#define rALMMIN (*(volatile unsigned char *)0x57000058)/Alarm minute#define rALMHOUR (*(volatile unsigned char *)0x5700005c)/Alarm Hour#define rALMDATE (*(volatile unsigned char *)0x57000060)/Alarm date / edited by junon#define rALMMON (*(volatile unsigned char *)0x57000064)/Alarm month#define rAL
25、MYEAR (*(volatile unsigned char *)0x57000068)/Alarm year#define rRTCRST (*(volatile unsigned char *)0x5700006c)/RTC round reset#define rBCDSEC (*(volatile unsigned char *)0x57000070)/BCD second#define rBCDMIN (*(volatile unsigned char *)0x57000074)/BCD minute#define rBCDHOUR (*(volatile unsigned cha
26、r *)0x57000078)/BCD hour#define rBCDDATE (*(volatile unsigned char *)0x5700007c)/BCD date /edited by junon#define rBCDDAY (*(volatile unsigned char *)0x57000080)/BCD day /edited by junon#define rBCDMON (*(volatile unsigned char *)0x57000084)/BCD month#define rBCDYEAR (*(volatile unsigned char *)0x57
27、000088)/BCD year#endif /RTCl 其中volatile 是C的保留字,通知编译器,不要自动优化这个地址所对应的变量值为0,因为寄存器的值往往是有含义的,并且是由硬件自动来设置的.强制设为0可能会带来错误.l #define rRTCCON (*(volatile unsigned char *)0x57000043)/RTC control 表示取地址0x57000043对应内存的地址l volatile unsigned char *, volatile unsigned short *, volatile unsigned int * 表示处理对应地址的宽度/范围,
28、分别是1,2,4 Byte,在寄存器地址强制转换成哪一种类型,取决于这一寄存器的有效位,如rRTCCON 只用到4位,转换成一个char * 即可l 所有有寄存器用unsigned 来强制因为寄存器里所有位都是有效的数据位.而有符号会把最高位看成符号位.这样经常容易产生错误,l 用unsigned 另外要还要考虑到有符号右移位操作符号位不动,即算术右移.在底层编程往往是错误的.接着可以参考CPU手册的寄存器详细定义(457页),其中描述了每一位的格式.接着按程序初始化一个固定的年月日void RTC_Time_Set( void )rRTCCON = 1 ;/RTC read and writ
29、e enablerBCDYEAR = 0x05 ;/年 rBCDMON = 0x06 ;/月 rBCDDATE = 0x19 ;/日rBCDDAY = 0x02 ;/星期rBCDHOUR = 0x15 ;/小时 rBCDMIN = 0x21 ;/分 rBCDSEC = 0x30 ;/秒 /1取反,表示0x11111110 ,与上rRTCCON表示把最低0位置0,其余位不变rRTCCON &= 1 ;/RTC read and write disable /置1采用或操作 /rRTCCON |= 1; 读取时间电路void RTC_Display(void) U16 year ;U8 month
30、, day ;/ weekU8 hour, minute, second ;RTC_Time_Set() ; Uart_Printf( RTC TIME Display, press ESC key to exit !n ) ; while( Uart_GetKey() != ESC_KEY ) rRTCCON = 1 ;/RTC read and write enableyear = 0x2000+rBCDYEAR ;/年 month = rBCDMON ;/月 day = rBCDDATE ;/日/week = rBCDDAY ;/星期hour = rBCDHOUR ;/小时 minute
31、 = rBCDMIN ;/分 second = rBCDSEC ;/秒rRTCCON &= 1 ;/RTC read and write disable Uart_Printf( RTC time : %04x-%02x-%02x %02x:%02x:%02xn, year, month, day, hour, minute, second );Delay( 900 ) ; 嵌入式C语言寄存器定义解释参见寄存器定义#ifdef _BIG_ENDIAN#define rBCDSEC (*(volatile unsigned char *)0x57000070)#else从上述定义中,请思考,如下
32、问题l 为什么要分字节序符定义?l volatile表示什么含意?l 为什么要用无符号的数字?l 宏定义的最前面*表示什么含意?l 为什么要分字节序符定义?寄存器的地址位于一个线性空间上.但是不同字节序下,同一寄存器的地址会发生变化.这可参见CPU的手册,为了隐藏这个细节,所以定义两套.另外,我们已经32位寄存器的各个位的固定的.不同的CPU字节序有不同结果,这样进行对位操作时.同一个寄存值在不同字节序下,会产生不同位排列.因此为防止字节序对寄存器进行干扰.后面的ADS 的C代码一般会直接采用大端字节序.在Linux下很多时候会采用移位来排除字节序的干扰.l volatile表示什么含意?vo
33、latile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。volatile区分C程序员和嵌入式系统程序员的最基本的问题。搞嵌入式的家伙们经常同硬件、中断、RTOS等等打交道,所有这些都要求用到volatile变量。不懂得volatile的内容将会带来灾难。当要求使用volatile 声明的变量的值时,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。如果一个变量没有volatile
34、,编译器会自动进行优化,比如说自动清0.如果这个整数是一个多线程,或硬件地址.这样可能会带来意想不到结果.Volatile的应用场合l 存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义,如并行设备的硬件寄存器(如:状态寄存器)l 中断服务程序中修改的供其它程序检测的全局变量需要加volatile,如一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)l 多任务环境下各任务间共享的数据,如多线程应用中被几个任务共享的变量 l 为什么要用无符号的数字?我们知道,数字有两种移位,一种是算术移位,一种逻辑移位.其中前者在有符
35、号位的情况下,会对符号位做特殊处理.而且寄存器对应就是原始位,最高位也有特定的含意.这种情况下,指定为无符号位数是了防止编译器对最高位采用特殊算术移位.从而违反了设计者的本意.l 宏定义的最前面*表示什么含意?表示取指针的内容,类似于 char *p=&a; *p=A,但这里不是一个变量,而且是一个常量地址.但效果是一样的,相当于取对应地址的内容.或者这个地址赋值寄存器操作因为每个寄存器都32位宽,因此在程序中可把寄存器的值看成一个无符号整数,对寄存器的取值看成是取一个整数值,而对寄存器设置看成是对一个整数变量赋值.l 置某一位为01置第一位为0/1取反,表示0x11111110 ,与上rRT
36、CCON表示把最低0位置0,其余位不变rRTCCON &= 1 ;/RTC read and write disable 2.置第三位为0 /0x0100 取反。再与上相应的寄存器地址 rRTCCON &= 0x4; 3假设置 12-13 bit的为0 ,则二进制展开为 11000000000000,换算为 0x3000 rADCDAT0 &=0x3000; 4.置采用左移,或右移来置位,以置14bit为0例 rADCDAT0 &=(0x114);l 置某一位11置第一位为1/1取反,表示0x00000001 ,或上rRTCCON表示把最低0位置1,其余位不变rRTCCON |= 1 ;/RT
37、C read and write disable 2.置第三位为1 /0x0100,再或上相应的寄存器地址 rRTCCON |= 0x4; 3假设置 12-13 bit的为1 ,则二进制展开为 11000000000000 rADCDAT0 |=0x3000; 4.置采用左移,或右移来置位,以置14bit为1例 rADCDAT0 |=(0x114);l 取位操作。1. 假设是否判断rADCDAT0的第14位的值。 if( rADCDAT0 & (0x0112; 以初始化一个Nand Flash 为例.#define TACLS 0x01rNFCONF = (TACLS12)|(TWRPH08)|(TWRPH14)|(00);rNFCONT = (013)|(012)|(010)|(09)|(08)|(16)|(15)
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
评论
0/150
提交评论