![嵌入式系统原理与开发(第三版)-(4)[113页]课件_第1页](http://file4.renrendoc.com/view/7eca7269e1dedb91af24ddd73085d19b/7eca7269e1dedb91af24ddd73085d19b1.gif)
![嵌入式系统原理与开发(第三版)-(4)[113页]课件_第2页](http://file4.renrendoc.com/view/7eca7269e1dedb91af24ddd73085d19b/7eca7269e1dedb91af24ddd73085d19b2.gif)
![嵌入式系统原理与开发(第三版)-(4)[113页]课件_第3页](http://file4.renrendoc.com/view/7eca7269e1dedb91af24ddd73085d19b/7eca7269e1dedb91af24ddd73085d19b3.gif)
![嵌入式系统原理与开发(第三版)-(4)[113页]课件_第4页](http://file4.renrendoc.com/view/7eca7269e1dedb91af24ddd73085d19b/7eca7269e1dedb91af24ddd73085d19b4.gif)
![嵌入式系统原理与开发(第三版)-(4)[113页]课件_第5页](http://file4.renrendoc.com/view/7eca7269e1dedb91af24ddd73085d19b/7eca7269e1dedb91af24ddd73085d19b5.gif)
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第4章 BootLoader与设备驱动 4.1 引言 4.2 BootLoader 4.3 设备驱动 思考与练习题4.1 引 言嵌入式软件的体系结构包括驱动层、操作系统层、中间件层和应用层,如图4-1所示。图4-1 嵌入式软件的体系结构其中,驱动层直接与硬件相关,为操作系统和应用程序提供支持。可以将驱动层软件分为三种类型:(1) 板级初始化程序:在系统上电后,初始化系统的硬件环境,包括嵌入式微处理器、存储器、中断控制器、DMA和定时器等。(2) 与系统软件相关的驱动程序:用于支持操作系统和中间件等系统软件所需的驱动程序。嵌入式微处理器已经提供了操作系统内核所需的硬件支持,因此开发人员一般所需编
2、写的驱动程序主要是键盘、显示器、外存、网络等外部设备的驱动程序。(3) 与应用软件相关的驱动程序:不一定要与操作系统连接,其设计和开发由应用所决定。4.2 BootLoader4.2.1 BootLoader概述BootLoader是系统加电后首先运行的一段程序代码,其目的是将系统的软、硬件环境带到一个合适的状态,为调用操作系统内核准备好正确的环境。对于不使用操作系统的嵌入式系统而言,应用程序的运行同样也需要依赖这样一个准备良好的软、硬件环境,因此从这个意义上来讲,Boot Loader对于嵌入式系统是必需的。BootLoader是依赖于目标硬件实现的,这可以从以下两个方面来理解:(1) 每种
3、嵌入式微处理器的体系结构都有不同的Boot Loader。当然,有些BootLoader也可以支持多种体系结构的嵌入式微处理器。如U-Boot可同时支持ARM体系结构和MIPS体系结构。(2) BootLoader还依赖于具体的嵌入式板级硬件设备的配置。 1BootLoader的安装通常,BootLoader只有几千字节的大小,由于系统加电后需要首先运行这段程序,因此BootLoader需要放在系统加电后最先取指令的地址上。嵌入式处理器的生产厂商都为处理器预先安排了一个在系统加电或复位后最先取指令的地址。例如,基于ARM7 TDMI内核的处理器在加电或复位时都从地址0 x00000000取第一
4、条指令。基于嵌入式微处理器构建的嵌入式系统通常都设计有某种类型的固态存储设备,如ROM、EEPROM、Flash等。BootLoader被安装到这种存储设备上,这个存储设备又被映射到预先安排的最先取指令的地址上。这样,就可以保证系统加电或复位之后,首先运行BootLoader程序。其实,这与PC机的BIOS(Basic Input/Output System)的启动原理是一致的。不同的是,由于BootLoader的体积很小,而嵌入式系统的存储资源受限,很多情况下,BootLoader与操作系统内核、根文件系统甚至应用程序等都可以烧写在同一个存储芯片上。图4-2所示是典型的固态存储设备的空间分配
5、结构。图4-2 固态存储设备的典型空间分配结构2BootLoader的操作模式对于开发人员而言,大多数BootLoader都包含两种操作模式:启动加载模式和下载模式。启动加载模式也称为自主(Autonomous)模式。在这种模式下,BootLoader从目标机的某个固态存储设备上将操作系统加载到RAM中运行,整个过程中没有用户的介入。这种模式是BootLoader的正常工作模式,在嵌入式产品发布的时候,显然需要让BootLoader工作在这种模式下。下载模式是指目标机上的BootLoader通过串口或网络连接等通信手段从宿主机上下载文件,如操作系统的内核映像和根文件系统的映像等。3BootLo
6、ader的控制设备和机制从开发的角度来看,BootLoader程序必须与宿主机之间建立起至少一种通信方式,这也是将来第一次加载操作系统内核的唯一手段。通常,开发人员都会采用串口首先建立起目标机与宿主机之间的联系,这是因为与其他通信方式相比,串口通信最容易实现。BootLoader程序在执行时也就可以利用这个简单实现的串口通信进行I/O操作,与外界交换数据和信息。文件的传输也可以通过串口完成。传输协议通常采用xmodem/ymodem/zmodem中的一种。但是,用串口进行文件传输,速度比较慢。因此,习惯的做法是在Boot Loader中实现TFTP协议,在宿主机上利用TFTP的软件工具,通过以
7、太网连接来下载文件。4.2.2 BootLoader的典型结构如上所述,BootLoader的主要任务就是建立起调用操作系统内核、运行用户应用程序所需要的良好的软、硬件环境。这个任务具体包括两部分的内容:硬件设备初始化和建立内存空间的映射图。下面以基于ARM7 TDMI内核的S3C4510B为例具体介绍BootLoader的启动过程。在启动过程中,BootLoader依次初始化CPU在各种模式下的堆栈空间、设定CPU的内存映射、对系统的各种控制寄存器进行初始化、对CPU的外部存储器进行初始化、设定各外围设备的基地址、创建正确的中断向量表、为C代码执行创建ZI(零创建)区,然后进入到C代码。在C
8、代码中继续对时钟、RS-232端口进行初始化,然后打开系统中断允许位。最后进入到应用代码中执行,执行期间响应各种不同的中断信号并调用预先设置好的中断服务程序处理这些中断。整个过程的流程图如图4-3所示。图4-3 启动代码流程图1堆栈初始化堆栈初始化要做的事情是为处理器的7个处理器模式分配堆栈空间。下面是FIQ模式下的堆栈设置:2DRAM初始化DRAM的初始化是根据系统配置信息决定的,系统不一定会用到DRAM,但是一定要做SDRAM的初始化。主要的处理内容是ROM和RAM基地址的设定、数据总线宽度的设定、SDRAM刷新时间的设定等,这些设定可以参照S3C4510B芯片的用户手册来进行。3设置特殊
9、寄存器特殊寄存器的设置主要是针对I/O口的,如设定几个I/O位,用作系统状态指示灯LED等。寄存器的设定主要根据硬件的配置情况而定,需要注意的是由于启动代码是烧录到ROM中的,而中断向量必须位于零地址,因此在存储单元没有重新映射之前ROM基址的设定应该为零地址。4拷贝镜像文件拷贝镜像文件的目的主要是为了提高运行速度。将编译生成的镜像文件代码从ROM拷贝到RAM中后,程序的执行也就在RAM中了。当然,如果启动代码对运行速度的要求不是很严格,那么这个拷贝过程可以省略,让代码存放在ROM中,代码的执行也在ROM中,而把运行所需的数据放在RAM中。5内存初始化内存初始化的目的是为C代码的运行开辟内存区
10、。我们已经知道,代码编译后会分为三个区:只读区、可读/可写区和零初始化区。内存初始化处理的内容是:当只读区截止地址等于可读可写区基址时,把零初始化区各字节清零;当只读区截止地址不等于可读/可写区基址时,如果可读/可写区基址小于零初始化基址,就从只读区截止地址处开始把数据拷贝到可读/可写区基址处,直到到达零初始化基址,然后把零初始化区各字节清零,否则只需把零初始化区各字节清零。6建立中断向量表中断向量表用于处理异常情况,当发生异常时,首先要保存当前程序的返回地址和CPSR寄存器的值,然后进入到相应的异常向量地址。一般来说,在异常向量地址处是一个跳转指令,使程序进入相应的异常处理过程。由于中断向量
11、表要位于系统的零地址,当把启动代码烧录到EEPROM中运行时就需要把ROM的地址定义到零地址,因此程序入口处的跳转指令分别是:7系统重新映射系统重新映射与前面镜像文件的拷贝有关。当为了提高运行速度把ROM的镜像文件拷贝到RAM后,中断向量表就不在零地址处了,因此要重新映射存储单元,把RAM的地址重新设定为零地址。整个过程是把启动代码从ROM(EEPROM或者Flash Memory)拷贝到SDRAM中运行,同时在拷贝完毕后进行内存的重新映射,把SDRAM映射到原来的ROM地址(0 x00000000)中,这样就可以用SDRAM中的代码写Flash Memory,使得程序代码得以更新。但是需要注
12、意的是, 如果程序进行了映射, 那么就对在线调试带来了困难, 使得在线调试不可以在RAM中进行。如果写入EEPROM的代码是被映射了的,则在调试器启动的时候必然也会对程序进行映射,使得程序在调试器中不能定位到原来的地方,导致调试失败。一个折中的方法是,不进行映射,即在调试的代码中不使用下载,这样就可以像普通的代码一样进行调试了。8切换到用户模式,进入C代码区完成以上的初始化工作后,让CPU切换到用户模式下,并把堆栈指针SP指定到用户堆栈区,就可以进入到C代码区运行了。在C代码中继续对时钟、RS-232端口进行初始化,然后打开系统中断允许位,进入到应用代码中执行。从程序结构上来讲,BootLoa
13、der一般都分为Stage1和Stage2两部分。Stage1存放依赖于CPU体系结构的代码(如设备初始化代码等),通常使用汇编语言来实现,达到短小精悍的目的。Stage2用来实现复杂功能,通常使用C语言来实现,使代码具有更好的可移植性。与普通C语言程序不同的是,在编译和链接BootLoader这样的程序时,不能使用glibc库中的任何支持函数。对照上述S3C4510B的启动过程,Stage1部分的代码依次实现以下功能:(1) 硬件设备初始化。(2) 为加载Stage2程序准备RAM空间。(3) 拷贝Stage2程序到RAM空间。(4) 设置好堆栈。(5) 跳转到Stage2的C程序入口点。S
14、tage2部分的代码依次实现的功能如下:(1) 初始化本阶段用到的硬件设备,如RS-232。(2) 检测系统内存映射。(3) 将操作系统内核映像和根文件系统映像从Flash Memory读到RAM空间中。(4) 为操作系统内核设置启动参数。(5) 调用操作系统内核。4.2.3 实例分析本小节以基于ARM7 TDMI内核的S3C44B0X为例详细介绍BootLoader的设计与实现。它与S3C4510B不同的是:S3C44B0X没有存储器重映射的功能,所有存储区地址固定。另外,S3C44B0X提供了矢量中断的功能,扩展了向量表(采用矢量中断可以减少中断延迟)。实例程序如下:;*;*;文件名:Sy
15、sInit.s;说明:硬件初始化程序;编译环境:ADS 1.2;*;*;存储器空间;GCS664M 16bit(8MB) DRAM/SDRAM(0 xC0000000 xC7FFFFF);存储器空间;存储器控制预定义REFRESHEQU 0 x01C80024;*;BDMA目的寄存器BDIDES0EQU 0 x1F80008BDIDES1EQU 0 x1F80028;*;预定义常数(常量)USERMODEEQU0 x10FIQMODEEQU0 x11IRQMODEEQU0 x12SVCMODEEQU0 x13ABORTMODEEQU0 x17UNDEFMODEEQU0 x1B;为BDMA改变B
16、DMACON的复位值LDRR0, =BDIDES0LDRR1, =0 x40000000;BDIDESn的复位值应当为0 x40000000STRR1, R0LDRR0, =BDIDES1LDRR1, =0 x40000000;BDIDESn的复位值应当为0 x40000000STRR1, R0;*;设定存储器控制寄存器ADRR0, InitSystemLDRR1, =InitSystemSUBR0, R1, R0LDRR1, =SMRDATASUBR0, R1, R0LDMIA R0, R1-R13LDRR0, =0 x01C80000;BWSCON的地址STMIA R0, R1-R13;*
17、;初始化堆栈MRSR0, CPSRBICR0, R0, #MODEMASKORRR1, R0, #UNDEFMODE|NOINTMSRCPSR_CXSF, R1;UndefModeLSRSP, =UndefStackORRR1, R0, #ABORTMODE|NOINTMSRCPSR_CXSF, R1;AbortModeLSRSP, =AbortStackORRR1, R0, #IRQMODE|NOINTMSRCPSR_CXSF, R1;IRQModeLSRSP, =IRQStackORRR1, R0, #FIQMODE|NOINTMSRCPSR_CXSF, R1;FIQModeLSRSP,
18、=FIQStackORRR1, R0, #SVCMODE|NOINTMSRCPSR_CXSF, R1;SVCModeLSRSP, =SVCStack;USER mode is not initialized.;*;在配置好RAM后,设置IQR处理程序入口LDRR0, =IRQ_SVC_VECTORLDRR1, =IRQ_SERVICESTRR1, R0;*MOV PC, LR;返回;*SMRDATA DATA;*;* memory access cycle parameter strategy *; 1) Even FP-DRAM, EDO setting has more late fetc
19、h point by half-clock.; 2) The memory settings, here, are made the safe parameters even at 66MHz.; 3) FP-DRAM Parameters: tRCD=3 for tRAC, tcas=2 for pad delay, tcp=2 for bus load.; 4) DRAM refresh rate is for 40MHz. ;bank016bit BOOT ROM;bank18bit NandFlash;bank2MAC0;bank3MAC1;bank4rtl8019;bank5ext;
20、bank616bit SDRAM;bank716bit SDRAM BUSWIDTH=16DCD 0 x11110001;Bank0=16bit BootRom(AT29C010A*2) :0 x0 old 0 x11110101 | ;BUSWIDTH=32DCD 0 x22222220;Bank0=OM1:0, Bank1Bank7=32bit ;GCS0GCS5内存分配代码从略 BDRAMTYPE=DRAMDCD(B6_MT15)+(B6_Trcd4)+(B6_Tcas3)+(B6_Tcp2)+(B6_CAN);GCS6 check the MT value in parameter.a
21、DCD(B7_MT15)+(B7_Trcd4)+(B7_Tcas3)+(B7_Tcp2)+(B7_CAN);GCS7| ;SDRAMDCD(B6_MT15)+(B6_Trcd2)+(B6_SCAN);GCS6DCD(B7_MT15)+(B7_Trcd2)+(B7_SCAN);GCS7DCD(REFEN23)+(TREFMD22)+(Trp20)+(Trc18)+(Tchr16)+REFCNT);REFRESH RFEN=1, TREFMD=0, trp=3clk, trc=5clk, tchr=3clk,count=1019DCD0 x10;SCLK power down mode, BANK
22、SIZE 32M/32MDCD0 x20;MRSR6 CL=2clkDCD0 x20;MRSR7ALIGN;*;下面的函数用来进入掉电模式,具体代码从略;*void EnterPWDN(int CLKCON)EnterPWDN ;*IRQ_SERVICE;using I_ISPR register.IMPORTpIrqStartIMPORTpIrqFinishIMPORTpIrqHandler;IMPORTANT CAUTION!;if I_ISPC isnt used properly, I_ISPR can be 0 in this routine.LDRR4, =I_ISPR LDRR4
23、, R4CMPR4, #0 x0 ;If the IDLE mode work-around is used, R0 may be 0 sometimes.BEQ%F3LDRR5, =I_ISPC STRR4, R5;clear interrupt pending bit LDRR5, =pIrqStart LDRR5, R5 CMPR5, #0 MOVNELR, PC; .+8 MOVNEPC, R5 MOVR0, #0 x00 MVOSR4, R4, LSR #1 BCS%F1 ADDR0, R0, #1 B%B01 LDRR1, =pIrqHandler LDRR1, R1 CMPR1,
24、 #0 MOVNELR, PC MOVNEPC, R12LDRR0, =pIrqFinishLDRR0, R0CMPR0, #0MOVNELR, PC; +8 MOVNEPC, R0 CMPR0, #0MOVNELR, PCMOVNEPC, R03LDMFDSP!, R0;从IRQ返回MSRSPSR_CXSF, R0LDMFDSP!, R0-R12, PC ;*EXPORTIrqHandlerTabIrqHandlerTabDCDHandleADC;*AREA RamData, DATA, READWRITE;这部分代码省略,主要是包括各种初始化的数据,如各个处理器模式使用堆栈的起始地址、;异
25、常向量、初始化向量表等;*END;*;*;文件名:Vector.s;说明:启动程序;编译环境:ADS 1.2;*;*ModeMask EQU0 x1FSVC32ModeEQU0 x13IRQ32ModeEQU0 x12FIQ32ModeEQU0 x11User32ModeEQU0 x10Abort32ModeEQU0 x17Undef32ModeEQU0 x1BIRQ_BITEQU0 x80FIQ_BITEQU0 x40GBLSMainEntryMainEntrySETS“main”IMPORT$MainEntry ;*;检查是否使用tasm.exe进行编译GBLL THUMBCODE CON
26、FIG = 16THUMBCODE SETLTRUE CODE32 |THUMBCODE SETLFALSE THUMBCODE CODE32 ;for start-up code for Thumb mode AREASelfBoot, CODE, READONLY IMPORTUDF_INS_VECTORIMPORTSWI_SVC_VECTORIMPORTINS_ABT_VECTORIMPORTDAT_ABT_VECTORIMPORTIRQ_SVC_VECTORIMPORTFIQ_SVC_VECTOR;这些向量在SysInit.s的数据段中已被初始化ENTRYIF :DEF: |ads$v
27、ersion|ELSEEXPORT_main_mainENDIFResetEntry;*MACRO$LabelHANDLER$Vector$LabelSUBLR, LR, #4STMFDSP!, R0-R3, LRLDRR0, =$VectorLDRPC, R0LDMFDSP!, R0-R3, PCMENDUDF_INS_HANDLER STMFDSP!, R0-R3, LRLDRR0, =UDF_INS_VECTORMOVLR, PCLDR PC, R0LDMFDSP!, R0-R3, PCSWI_SVC_HANDLER;各种异常处理,以下代码从略INS_ABT_HANDLERDAT_ABT
28、_HANDLERIRQ_SVC_HANDLERFIQ_SVC_HANDLER;*SYS_RST_HANDLERMRSR0, CPSR;enter SVC mode and disable IRQ,FIQBICR0, R0, #ModeMaskORRR0, R0, #(SVC32Mode :OR: IRQ_BIT :OR: FIQ_BIT)MSRCPSR_C, R0IMPORTInitSystemBLInitSystem ADRR0, ResetEntryLDRR1,BaseOfROMCMPR0,R1LDREQR0, TopOfROMBEQInitRamDataLDRR2,=CopyProcBe
29、gSUBR1, R2, R1ADDR0, R0, R1LDRR3,=CopyProcEnd0LDMIAR0!, R4-R7STMIAR2!, R4-R7CMPR2, R3BCC%B0 LDRR3, TopOfROMLDRPC, =CopyProcBeg ;*CopyProcBeg0LDMIAR0!, R4-R11STMIAR2!, R4-R11CMPR2, R3BCC%B0CopyProcEndSUBR1, R2, R3SUBR0, R0, R1 InitRamDataLDRR2, BaseOfBSSLDRR3, BaseOfZero0CMPR2, R3LDRCCR1, R0, #4STRCC
30、R1, R2, #4BCC%B0 MOVR0,#0LDRR3,EndOfBSS1CMPR2,R3STRCCR0, R2, #4BCC%B1 LDRPC,GotoMain GotoMainDCD$MainEntry ;*IMPORT|Image$RO$Base|; ROM code startIMPORT|Image$RO$Limit|; RAM data starts after ROM programIMPORT|Image$RW$Base|; Pre-initialised variablesIMPORT|Image$ZI$Base|; uninitialised variablesIMP
31、ORT|Image$ZI$Limit|; End of variable RAM space BaseOfROMDCD|Image$RO$Base|TopOfROMDCD|Image$RO$Limit|BaseOfBSSDCD|Image$RW$Base|BaseOfZeroDCD|Image$ZI$Base|EndOfBSSDCD|Image$ZI$Limit|EXPORTGetBaseOfROMEXPORTGetEndOfROMEXPORTGetBaseOfBSSEXPORTGetBaseOfZeroEXPORTGetEndOfBSS GetBaseOfROMLDRR0, BaseOfRO
32、MMVOPC, LRGetEndOfROM;以下代码从略GetBaseOfBSSGetBaseOfZeroGetEndOfBSS;*END受篇幅所限,C代码部分从略。这里只列出在C代码中实现的若干重要函数:ChgSysMclk设置系统主频ProgFlash从RAM向Flash Memory加载的工具MoveFlashToRam从Flash Memory向RAM加载的工具GetDate设置日期,打印输出SetWeek设置星期,打印输出GetTime设置时间,打印输出ChgBaudRate设置串口波特率LoadFromUart串口通信SetIPAddr设置IP地址tftp_maintftp服务器G
33、etParameter获取键值,作相应处理RunProgram选择执行的程序ParseArgs和ParseCmd命令解析Help使用帮助当然,还可以使用C语言编程为BootLoader增加更有趣的功能。4.3 设 备 驱 动4.3.1 设备驱动概述使用任何外部设备时都需要有相应驱动程序的支持。驱动程序为上层软件提供设备的操作接口。对于上层软件而言,只需要调用驱动程序提供的接口,而不用理会设备具体的内部操作。对于驱动程序而言,不仅要实现设备的基本功能函数,如初始化、中断响应、发送、接收等,使设备的基本功能得以实现,而且针对设备使用过程中可能出现的各种差错,还应提供完备的错误处理函数。驱动层软件有
34、两个重要的概念:硬件抽象层(Hardware Abstraction Layer,HAL)和板级支持包(Board Support Package,BSP)。可以简单地理解为硬件抽象层与硬件具有更加紧密的相关性,而板级支持包与操作系统具有更加紧密的相关性。具体地讲,硬件抽象层的目的是为了将硬件抽象化,即通过程序来控制诸如CPU、I/O、存储器等硬件的操作,从而使得系统的设备驱动程序与硬件无关。 设计板级支持包的目的主要是为驱动程序提供访问硬件设备寄存器的函数包,从而实现对操作系统的支持。为保证与操作系统保持正确的接口,以便良好地支持操作系统,不同的操作系统应对应不同定义形式的板级支持包。在功能
35、上,板级支持包大体需要实现以下两方面的内容:(1) 在系统启动时,完成对硬件的初始化。 (2) 为驱动程序提供访问硬件的手段。 在对硬件进行初始化时,BSP一般应完成以下工作:(1) 将系统代码定位到CPU将要跳转执行的内存入口处,以便在硬件初始化完毕后CPU能够执行系统代码。此处的系统代码可以是嵌入式操作系统的初始化入口,也可以是应用代码的主函数入口。(2) 根据不同CPU在启动时的硬件规定,BSP要负责将CPU设置为特定状态。(3) 对内存进行初始化,根据系统的内存配置将系统的内存划分为代码、数据、堆栈等不同的区域。(4) 如果有特殊的启动控制代码,则BSP要负责将控制权移交给启动控制代码
36、。(5) 如果应用软件中包含一个嵌入式操作系统,则BSP要负责将操作系统需要的模块加载到内存中。嵌入式应用软件系统在进行固化时,可以有基于ROM的和常驻ROM的两种方式,在基于ROM方式时,系统在运行时要将ROM或Flash Memory内的代码全部加载到RAM内;在常驻ROM方式时,代码可以在ROM或Flash Memory内运行,系统只将数据部分加载到RAM内。(6) 如果应用软件中包含一个嵌入式操作系统,则BSP还要在操作系统初始化之前,将硬件设置为静止状态,以避免造成操作系统初始化失败。在为驱动程序提供访问硬件的手段时,BSP一般应完成以下工作:(1) 将驱动程序提供的ISR(中断服务
37、程序)挂载到中断向量表上。(2) 创建驱动程序初始化所需要的设备对象。BSP将硬件设备描述为一个数据结构。这个数据结构中包含这个硬件设备的一些重要参数,上层软件就可以直接访问这个数据结构。(3) 为驱动程序提供访问硬件设备寄存器的函数。(4) 为驱动程序提供可重用性措施,比如将与硬件关系紧密的处理部分在BSP中完成,驱动程序直接调用BSP提供的接口,这样驱动程序就与硬件无关。只要不同的硬件系统的BSP提供的接口相同,驱动程序就可在不同的硬件系统上运行。下面以一个ARM的串行口驱动函数为例来了解一下设备驱动的原理与简单实现。/*UART的初始化*/void Uart_Init(int Uartn
38、um, int mclk, int baud)int i; if(mclk=0)mclk=MCLK;if(Uartnum=0)/UART0rUFCON0=0 x0;/FIFO disablerUMCON0=0 x0;/UART0 rULCON0=0 x3;/Normal,No parity,1 stop,8 bitrUCON0=0 x245;/rx=edge,tx=level,disable timeout int.,enable/rx error int.,normal,interrupt or pollingrUBRDIV0=(int)(mclk/16./baud + 0.5) -1);e
39、lserUFCON1=0 x0;rUMCON1=0 x0;/UART1rULCON1=0 x3;rUCON1=0 x245;rUBRDIV1=(int)(mclk/16./baud + 0.5) -1); for(i=0;i100;i+);/*UART的发送*/void Uart_SendByte(int Uartnum, U8 data)if(Uartnum=0) while(!(rUTRSTAT0 & 0 x2);/Wait until THR is empty.Delay(1);WrUTXH0(data); else while(!(rUTRSTAT1 & 0 x2);/Wait unt
40、il THR is empty.Delay(1);WrUTXH1(data); void Uart_SendString(int Uartnum, char *pt)while(*pt)if(*pt=n)Uart_SendByte(Uartnum, r);Uart_SendByte(Uartnum, *pt+); elseUart_SendByte(Uartnum, *pt+);void Uart_TxEmpty(int Uartnum)if(Uartnum=0)while(!(rUTRSTAT0 & 0 x4); /Wait until tx shifter is empty.elsewhi
41、le(!(rUTRSTAT1 & 0 x4); /Wait until tx shifter is empty./*UART的接收*/char Uart_Getch(char* Revdata, int Uartnum, int timeout)int i=0;if(Uartnum=0)while(!(rUTRSTAT0 & 0 x1); /Receive data read*Revdata=RdURXH0();return TRUE;elsewhile(!(rUTRSTAT1 & 0 x1);/Receive data read*Revdata=RdURXH1();return TRUE;/
42、If you dont use vsprintf(), the code size is reduced very much.void Uart_Printf(char *fmt,.) va_list ap; char string256; va_start(ap,fmt); vsprintf(string,fmt,ap); Uart_SendString(0, string); va_end(ap);说明:(1) 与UART有关的寄存器主要有:UART线性控制寄存器ULCONn、UART控制寄存器UCONn、读/写状态寄存器UTRSTAT、错误状态寄存器UERSTAT、FIFO状态寄存器UF
43、STAT、Modem状态寄存器UMSTAT、发送寄存器UTXH、接收寄存器URXH、波特率因子寄存器UBRDIV。(2) 由于ARM工作时存在大端和小端两种工作模式,因此同样一个寄存器在不同工作模式下的地址是不一样的,需要加以区别。具体的寄存器和特殊位的定义在头文件中,这里省略。4.3.2 LCD驱动控制实例与ARM自带LCD驱动器有关的寄存器包括PCOND(端口D的引脚配置寄存器)、PDATD(端口D的数据寄存器)、PUPD(端口D的上拉禁止寄存器)。其中,由于LCD驱动控制端口与ARM的端口4是共用的,因此要设置相应的寄存器,将其定义为LCD驱动控制端口。表4-1是LCD控制寄存器LCDC
44、ON1的位描述。我们选择的LCD的分辨率为320240,根据下面的公式可以计算出HOZVAL和LINEVAL的值,LINEBLANK设为15:在彩色模式下,水平显示范围=3水平像素数量。LINEVAL=垂直显示范围-1 (在单扫描显示形式下)设置OFFSIZE0,PAGEWIDTH320/2。下面是LCD驱动函数参考程序:#define LCDCON1_ENVID(1)#define LCDCON1_INVVD(11)#define LCDCON1_INVFRAME(12)#define LCDCON1_INVLINE(13)#define LCDCON1_INVCLK(14)#define
45、LCDCON1_MMODE(17)#define L248 (8)#define CLKVAL (20)/60MHz, fr=100Hz (CLKVAL=38.6)/#define M5D(n) (n) & 0 x1fffff)U32* pLCDBuffer16=(U32*)0 xc000000;U32 LCDBufferLCDHEIGHTLCDWIDTH;/*LCD初始化函数,设置各功能寄存器,清空显示缓存区*/void LCD_Init()int i;U32 LCDBASEU,LCDBASEL,LCDBANK; LCDDisplayOpen(FALSE); rLCDCON1=(0); /d
46、isablerLCDCON2=(239)|(11910)|(1522;LCDBASEU=0 x0;LCDBASEL=LCDBASEU+(160)*240;rLCDSADDR1=(0 x327)|(LCDBANK21)|LCDBASEU; /color_mode, LCDBANK, LCDBASEUrLCDSADDR2= (029)|(021)|LCDBASEL;rLCDSADDR3= (320/2)|(09); /No virtual screen. rREDLUT=0 xfca86420;rGREENLUT=0 xfca86420;rBLUELUT=0 xfffffa50;rLCDCON1=
47、LCDCON1_ENVID|01|02|03|(25)|17|(0 x38)|(0 x310)|(CLKVAL12);/|LCDCON1_MMODE; /enable,8B_SNGL_SCAN,WDLY=16clk,WLH=16clk,CLKVAL=?for(i=0;i80*240;i+)*(pLCDBuffer16+i)=0 x0;Delay(5000);LCDDisplayOpen(TRUE);void LCDDisplayOpen(U8 isOpen)if(isOpen)rPDATB&=LCDDisplayPin;elserPDATB|=LCDDisplayPin;*(pLCDBuffe
48、r16+i)=lcddata;在LCD上显示256色图形的关键是填充二级显示缓冲,将显示像素的24位颜色信息写入LCDBuffer。将R、G、B三种基本颜色按一定比例混合即可构成更复杂的颜色,每个像素的三种基本颜色分别占一个字节,可以方便地在程序里改写各基本颜色的数值,从而改变该像素的混合颜色。有兴趣的读者可以根据这个原理编写一个主函数来进行实验。4.3.3 A/D转换功能驱动实例ARM S3C440BX芯片自带一个路模拟信号输入的10位A/D转换器,该转换器通过软件编程选择设置为Sleep模式时,可以节电,减少功率损失。它的主要特性是最大转换率为500千次每秒,非线性度为正负位,输入电压范围
49、为02.5 V,输入带宽为0100 Hz。1ADC(A/D Conversion)的引脚设置S3C440BX芯片与A/D功能有关的引脚如表4-6所示,其中AIN7:0为8路模拟采集通道,AREFT为参考正电压,AREFB为参考负电压,AVCOM为模拟共电压。图4-4 外部引脚配置参考2ADC转换时间的计算A/D转换时间即完成一次A/D转换所需要的时间。如果系统时钟为66 MHz且ADC时钟源的预分频值为9,则10位数字量的转换时间为式中,除以16是因为要完成转换至少需要16个时钟周期。该ADC不具有采样-保持电路,因此虽然它具有较高的采样速度,但为了得到精确的转换数据,输入的模拟信号的频率应该
50、不超过100 Hz。3ADC相关寄存器及其设置与A/D转换相关的寄存器主要有如下三个:(1) ADCPSR:采样预分频寄存器。其地址和意义如表4-7所示。4. ADC驱动程序参考代码下面是ADC驱动函数参考程序。(1) 定义与ADC相关的控制位。#define ADCCON_FLAG0 x40#define ADCCON_SLEEP0 x20#define ADCCON_ADIN0(0 x02)#define ADCCON_ADIN1(0 x12)#define ADCCON_ADIN2(0 x22)#define ADCCON_ADIN3(0 x32)#define ADCCON_ADIN4
51、(0 x42)#define ADCCON_ADIN5(0 x52)#define ADCCON_ADIN6(0 x62)#define ADCCON_ADIN7(0 x72)#define ADCCON_READ_START0 x2#define ADCCON_ENABLE_START0 x1(2) ADC初始化函数。/*【功能说明】ADC转换时钟频率=2*(预分频值+1)*16 MCLK=64 MHz时,转换时间计算如下: 64/2*(20+1)/16=95.2kHz=10.5s*/void init_ADdevice(void) rADCPSR=20; /设置采样预分频寄存器ADCPSR rADCCON=ADCCON_SLEEP; /设置采样控制寄存器ADCCON,初始化ADC为睡眠模式(3) ADC数据转换。/*【功能说明】设置通道2进行ADC数据采样转换并返回转换结果*/int GetADresult(int channel) rADCCON=(channel2)|ADCCON_ENABLE_START; Delay(10); while(!(rADCCON & ADCCON_FLAG); /等待转换结束 return rADCDAT; /返回采样值(4) ADC中断服务。/*【功能说明】设置ADC为IRQ(普通中断请求)并编写中
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 养老合同附加合同范例
- 住宅消防保养合同范例
- 八年级学生数学语言转换能力调查研究
- 混联外骨骼肘腕康复机构运动性能及康复效果评估
- 机器人与3D导板辅助腰椎皮质骨轨迹置钉技术解剖应用研究
- 高压氧辅助治疗中老年2型糖尿病突发性聋患者的疗效分析
- 亮化报价合同范例
- 出租拆迁合同范例
- 代理雨鞋采购合同范例
- 中央空调主机大修合同范例
- 中职高教版(2023)语文职业模块-第一单元1.2宁夏闽宁镇:昔日干沙滩今日金沙滩【课件】
- 2025年春季1530安全教育记录主题
- 2024年国家公务员考试行测真题附解析答案
- 基本药物制度政策培训课件
- 《无人机测绘技术》项目1任务3无人机测绘基础知识
- 2024年新疆(兵团)公务员考试《行测》真题及答案解析
- 三级安全教育试题(公司级、部门级、班组级)
- (市级)数学活动:人教七下第5章《探究平行线的多种画法》教学设计(张佳琦-三门峡灵宝二中)
- 探讨延续性护理干预对老年高血压患者生活质量的影响
- 公司商业秘密管理办法
- (完整版)5m以上深基坑开挖施工方案
评论
0/150
提交评论