嵌入式设计及Linux驱动开发指南——基于ARM9处理器》

读书笔记

第一章嵌入式系统基础

1、 嵌入式系统定义:

“嵌入式系统是用来控制或者监视机器、装置、工厂等大规模系统的设备。”

——电气工程师协会

    “嵌入到对象体系中的专用计算机系统”

——北京航空航天大学何立民教授

    “嵌入性”、“专用性”与“计算机系统”是嵌入式系统的三个基本要素。

2、 嵌入式操作系统:

硬实时系统有一个刚性的、不可改变的时间限制,它不允许任何超出时限的错误超时错误会带来损害甚至导致系统失败、或者导致系统不能实现它的预期目标。

软实时系统的时限是柔性灵活的,它可以容忍偶然的超时错误。失败造成的后果并不严重,仅仅是轻微地降低了系统的吞吐量。

我们可以认为至少嵌入式系统都是软实时系统,所有的嵌入式系统都是实时系统,但并不是所有的实时系统都是嵌入式系统。

常用的嵌入式操作系统有:Linux, uC/OS, Windows CE, VxWorks, Palm OS, QNX等。

3、 选择Embedded OS的原则:

* 系统成本;

* 市场进入时间及技术支持;

* 可移植性;

* 可利用资源;

* 系统定制能力。



第二章 基于ARM9处理器的硬件开发平台

1、 ARM的历史:

ARM(Advanced RISC Machine)公司于1990年11月在英国剑桥成立。

1991年,ARM推出第一个嵌入式RISC核心——ARM6系列处理器,VLSI、夏普、GEC Plessey、德州仪器、Cirrus Logic等公司相继同ARM公司签署了授权协议。

1998年4月,ARM在伦敦证券交易所和纳斯达克交易所上市。

ARM中国安谋咨询上海有限公司于2002年7月在中国上海成立。

目前基于ARM核的处理器有以下几类:

* ARM7家族;

* ARM9家族;

* ARM9E家族;

* ARM10E家族;

* ARM11家族;

* SecurCore家族;

* OptimoDE数据引擎内核;

* MPCore多处理器家族;

* Intel公司的StrongARM/XScale。

  2、ARM7和ARM9处理器的主要区别:

    指令流水线:

ARM7:三级,(取指令,译码,执行);

ARM9:五级,(取指,译码,执行,缓冲/数据,回写)。

3、三星S3C2410X处理器:

基于ARM920T核(由ARM9TDMI、存储管理单元MMU和高速缓存三部分组成),片上资源包括:

* 1个LCD控制器(支持STN和TFT带有触摸屏的液晶显示屏);

* SDRAM控制器;

* 3个通道的UART;

* 4个通道的DMA;

* 4个具有PWM功能的计时器和1个内部时钟;

* 8通道的10位ADC;

* 触摸屏接口;

* I2S总线接口;

* 2个USB主机接口,1个USB设备接口;

* 2个SPI接口;

* SD接口和MMC卡接口;

* 看门狗计数器;

* 117位通用I/O口和24位外部中断源;



第三章 调试嵌入式系统程序

1、 嵌入式系统调试方法:

1) 实时在线仿真(In-Circuit Emulator, ICE)

* 优点:功能非常强大,软硬件均可做到完全实时在线调试。

* 缺点:价格昂贵。

2) 模拟调试

* 优点:简单方便,不需要目标板,成本低。

* 缺点:功能非常有限,无法实时调试。

3) 软件调试

* 优点:纯软件,价格较低,简单,软件调试能力较强。

* 缺点:需要事先烧制监控程序(Monitor)(往往需多次实验才能成功)且目标板工作正常,功能有限,特别是硬件调试能力较差。

4) JTAG调试

* 优点:方便、简单,无需制作Monitor,软硬件均可调适。

* 缺点:需要工作基本正常(至少CPU工作正常)的目标板,仅适用于有调试接口的芯片。

2、 ARM仿真器工作原理:

利用高速JTAG(Joint Test Action Group)串行扫描链,通过调试通信通道(Debug Communication Channel, DCC)连接ARM核心内嵌的名为“Embedded-ICE”的调试逻辑,调试逻辑实时监测ARM核心的寄存器、数据总线和地址总线。调试器设置Breakpoint及Watchpoint后,程序在ARM内核全速运行,调试程序实时监测地址与数据总线并与预设值比较,在吻合时产生异常中断通知内核并把控制权交给调试器。这样,在程序全速运行时,可以在断点处停止,可以设置条件断点、条件观测断点等,而又不占用CPU时间及内存资源。

3、 JTAG接口:

1985年制定的检测PCB和IC的一个标准,1990年被修改后成为IEEE的一个标准,及IEEE1149.1-1990。通过这个标准,可对具有JTAG接口芯片的电路进行边界扫描和故障检测。



第四章 创建嵌入式系统开发环境

1、交叉编译步骤:

(1) 创建编译环境。在这个过程中,将设置一些环境变量,创建安装目录,安装内核源代码和头文件等。



(2) 创建binutils。这个过程结束后,会创建类似arm-linux-ld等工具。

  Binutils是一组开发工具,包括链接器、汇编器以及其他用于目标文件和档案的工具

  首先要安装的软件包使binutils。这非常重要,因为glibc和gcc会针对可用的连接器和汇编器进行多种测试,以决定打开某些特性。

  

(3) 创建一个交叉编译版本的gcc。注意:在这个过程中只能编译C程序,而不能编译C++程序。

  创建交叉编译版本的gcc,需要交叉编译版本的glibc及其头文件,而交叉编译版本的glibc是通过交叉编译版本的gcc创建的。面对这个先有鸡还是先有蛋的问题,解决办法是先只编译对C语言的支持,并禁止支持线程。



(4) 创建一个交叉编译版本的glibc。这里最容易出现问题。

glibc是一个提供系统调用和基本函数的C语言库,比如open,malloc和printf等,所有动态链接的程序都要用到它。创建glibc需要的时间更长。 

(5) 创建一个交叉编译版本的gdb。在这个过程结束后,会创建ARM-Linux-gdb。 



(6) 重新创建gcc。前面创建gcc的过程没有编译C++编译器,现在glibc已经准备好了,所以这个步骤将完善gcc的交叉编译。





(7) 重新创建glibc。如果成功执行了这个过程,那么你就拥有了一套属于自己的交叉编译工具链。



2、如果在交叉编译过程中出现错误,那么请检查:

* 版本选择是否正确,以及是否安装了相应的补丁;

* 库文件路径是否正确;

* 系统环境变量是否设置正确。



第五章 Bootloader

1、 Bootloader(引导加载程序)是系统加电后运行的第一段代码。一般它只在系统启动时运行非常短的一段时间,但对于嵌入式系统来说,这是一个非常重要的系统组成部分。



2、 嵌入式Linux系统从软件的角度看通常可以分成4个层次:

(1) 引导加载程序。包括固化在固件(Firmware)中的启动代码(可选)和Bootloader两大部分。

(2) 内核。特定于嵌入式板子的定制内核以及控制内核引导系统的参数。

(3) 文件系统。包括根文件系统和建立于Flash内存设备之上的文件系统。通常用Ramdisk作为根文件系统。它是提供管理系统的各种配置文件以及系统执行用户应用程序的良好的运行环境的载体。

(4) 用户应用程序。特定于用户的应用程序。有时在用户应用程序和内核层之间可能还会包括一个嵌入式图形用户界面。



3、 Bootloader包含两种不同的操作模式:

1) 启动加载(Bootloading)模式;

2) 下载(Downloading)模式。



4、 Bootloader的启动流程:

第一阶段:主要包含依赖于CPU的体系结构硬件初始化的代码,通常都用汇编实现。这个阶段的任务有:

* 基本的硬件设备初始化(屏蔽所有的中断、关闭处理器内部指令/数据Cache等)

* 为第二阶段准备RAM空间

* 如果是从某个固态存储媒质中,则复制Bootloader的第二段代码到RAM

* 设置堆栈

* 跳转到第二阶段的程序入口点

第二阶段:通常用C语言完成,以便实现更复杂的功能,也使程序有更好的可读性和可移植性。这个阶段的任务有:

* 初始化本阶段要使用到的硬件设备

* 检测系统内存映射

* 将内核映像和根文件系统映像从FLASH读到RAM

* 为内核设置启动参数

* 调用内核



5、 常用U-Boot命令:

命令名

功能

help / ?

帮助命令。用于查询U-Boot支持的命令并列出简单说明,和“?”是同一个命令

bdinfo

察看目标系统参数和变量、目标板的硬件配置、各种变量参数

setenv

设置环境变量。比较常用的有:

setenv ipaddr *.*.*.*

setenv severip *.*.*.*

setenv gatewayip *.*.*.*

setenv ethaddr *.*.*.*.*.*

printenv

查看环境变量

saveenv

保存设置的环境变量到Flash

mw

写内存

md

察看内存

mm

修改内存

flinfo

察看Flash的信息

erase [起始地址 结束地址]

搽除Flash内容,必须以扇区为单位进行搽除

cp [源地址 目标地址 大小]

内存复制,可以在Flash和ram中交换数据

imi [起始地址]

察看内核映像文件

bootm [起始地址]

从某个地址启动内核

tftpboot [起始地址 镜像名]

通过ftp从主机系统下载内核映像文件

reset

复位



第六章 Linux系统在ARM平台的移植

1、 使某一个平台的代码运行在其它平台上的过程就叫做移植。

2、 Linux内核结构:

* /arch包含了所有硬件结构特定的内核代码。

Linux系统能支持如此多平台的部分原因是因为内河把原程序代码清晰的划分为体系结构无关部分和体系结构相关部分。对于任何平台,都必须包含以下几个目录:

* boot:包括启动内核所使用的部分或全部平台特有代码。

* kernel:存放支持体系结构特有的(如信号处理和SMP)特征的实现。

* lib:存放高速体系结构特有的(如strlen和memcpy)同用函数的实现。

* mm:存放体系结构特有的内存管理程序的实现。

* math-emu:模拟FPU的代码。对于ARM处理器来说,此目录用mach-xxx代替。

显然,移植工作的重点就是移植arch目录下的文件。

* /drivers包含了内核中所有的设备驱动程序。

* /fs包含了所有的文件系统的代码。

* /include包含了建立内核代码时所需的大部分库文件,这个模块利用其他模块重建内核。该目录也包含了不同平台需要的库文件。比如,asm-arm是arm平台需要的库文件。

* /init包含了内核的初始化代码,内核从此处工作。

不是系统的引导代码,由main.c和version.c两个文件。这是研究核心如何工作的好起点。

* /ipc包含了进程间通信代码。

* /kernel包含了主内核代码。

* /mm包含了所有内存管理代码。

* /net包含了和网络相关的代码。

3、 在移植过程中,定时器、中断、CACHE管理、MMU等和硬件密切相关的地方都是要相关平台的底层代码支持的,要特别注意。

4、 编译内核:

1) 配置内核

make ARCH=arm CROSS_COMPILE=arm-Linux- menuconfig

2) 创建内核依赖关系

make dep

3) 创建内核镜像文件

make zImage

4) 创建内核模块

make modules

make modules_install

对每一个配置来说,内核生成以后包括4个文件:没有压缩的内核镜像(zImage或bzImage),压缩的内核镜像(vmlinux),内核符号映射文件(System.map)以及配置文件(config)。



第七章 Linux设备驱动程序开发

1、 设备驱动的任务包括:

1) 自动配置和初始化子程序。这部分程序仅在初始化的时候被调用一次。

2) 服务于I/O请求的子程序。这部分是系统调用的结果。在执行这部分程序的时候,系统仍认为和进行调用的进程属于同一个进程,只是由用户态变成了核心态,并具有进行此系统调用的用户程序的运行环境,所以可以在其中调用sleep()等与进程运行环境有关的函数。

2、 设备类型分类:

1) 字符设备(char device)。字符设备是Linux最简单的设备,可以向文件一样访问。

  初始化字符设备时,它的设备驱动程序向Linux登记,并在字符设备向量表中增加一个device_struct数据结构条目,这个设备的主设备标识符用作这个向量表的索引。一个设备的主设备标识符是固定的。chrdevs向量表中的每一个条目,一个device_struct数据结构,包括两个元素:一个登记的设备驱动程序的名称的指针和一个指向一组文件操作的指针。参见include/linux/major.h。

2) 块设备(block device)。是文件系统的物质基础,它也支持像文件一样被访问。

  Linux用blkdevs向量表维护已经登记的块设备文件。它像chrdevs向量表一样,使用设备的主设备号作为索引。它的条目也是device_struct数据结构。与字符设备不同的是,块设备分为SCSI类和IDE类。类向Linux内核登记并向河心提供文件操作。一种块设备类的设备驱动程序向这种类提供和类相关的接口。参见fs/devices.c。

每一个块设备驱动程序必须提供普通的文件操作接口和对于buffer cache的接口。每一个块设备驱动程序填充blk_dev向量表中的blk_dev_struct数据结构。这个向量表的索引还是设备的主设备号。这个blk_dev_struct数据结构包括一个请求例程的地址和一个指针,指向一个request数据结构的列表,每一个都表达buffer cache向设备读/写一块数据的一个请求。参见drivers/block/ll_rw_blk.c和include/linux/blkdev.h。

当buffer_cache从一个已登记的设备读/写一块数据,或者希望读写一块数据到其他位置时,他救灾blk_dev_struct中增加一个request数据结构。每个request数据结构都有一个指向一个或多个buffer_head数据结构的指针,每一个都是读/写一块数据的请求。如果buffer_head数据结构被锁定(buffer_cache),可能会有一个进程在等待这个缓冲区的阻塞进成完成。每一个request数据结构都是从all_request表中分配的。如果request增加到空的request列表,就调用驱动程序的request函数处理这个request队列,否则驱动程序只是简单的处理request队列中的每一个请求。

块设备驱动程序和字符设备驱动程序的主要区别是:在对字符设备发出读写请求时,实际的硬件I/O一般紧接着就发生了,块设备则不然,它利用一块系统内存作为缓冲区,当用户进程对设备请求能满足用户的要求时,就返回请求的数据,如果不能就调用请求函数来进行实际的I/O操作。块设备是主要针对磁盘等慢速设备的,以免耗费过多地CPU时间来等待。

3) 网络设备。

3、 设备驱动中关键数据结构:

1) file_operations:内核内部通过file结构识别设备,通过file_operations数据结构提供文件系统的入口点函数。file_operations定义在 中的函数指针表。这个结构的每一个成员的名字都对应着一个系统调用。从某种意义上说,写驱动程序的任务之一就是完成file_operations中的函数指针。如果在2.4版本内核下开发的驱动很可能在2.6版本中无法使用,需要进行移植。

2) inode:文件系统处理的文件所需要的信息在inode(索引节点)中。

3) file:主要用于与文件系统对应的设备驱动程序使用。

 第八章 网络设备驱动程序开发

1、 网络设备使用网络接口管理表dev_base。dev_base是一个指向device结构的指针,因为网络设备是通过device数据结构来表示的。

2、 网络驱动程序必须解决的两个问题:

1) 不是所有建立在Linux内核的网络设备驱动程序都会有控制的设备。

2) 系统中的以太网设备总是叫做/dev/eth0到/dev/eth7,而不管底层的设备驱动程序是什么。当驱动程序找到它的以太网设备时,它就填充它现在拥有的ethn的device数据结构。这时网络驱动程序也要初始化它控制的物理硬件,并找出它使用的IRQ、DMA等。一旦所有的8个标准的/dev/ethn都分配了,就不会再探测更多的以太网设备。

3、 两个重要的数据结构:

1) device:这个数据结构是在系统中每一个设备的代表,它提供了多个设备方法,供操作系统或协议层使用。这其中就包括设备初始化时调用的init函数、打开和关闭设备的open和stop函数、处理数据包发送的hard_start_xmit函数等。

2) sk_buff:Linux网络各层之间的数据传送都是通过sk_buff(套接字缓冲区)完成的。每个sk_buff包括一些控制方法和一块数据缓冲区,这个区域存放了网络传输的数据包。控制方法按功能分为两种类型,一种是控制整个buffer链的方法,另一种是控制数据缓冲区的方法。sk_buff组成双向链表的形式,对链表的操作主要是删除链表头的元素和添加到链表尾。sk_buff数据结构再include/linux/skbuff.h文件中定义。

4、 内核的驱动程序接口:

1) 打开函数net_open:执行“ifconfig eth0 up”命令时网络层调用它,把设备连到线路上并启用来接受/发送数据。open函数在网络设备驱动程序里是网络设备被激活的时候被调用的,即设备状态由down至up。所以实际上很多在初始化的工作可以放到这里来做。

2) 关闭函数net_close:执行“ifconfig eth0 down”时使网卡进入一个清醒的状态。如果硬件许可那么它会释放中断和DMA通道,并完全关闭以节约能源。

3) 探测函数probe/probe1:在启动时调用以检测网卡存在与否。如果可以通过读取内存等非强制手段进行检查最好,也可以从I/O端口读取。在探测函数的最后它会填充device结构各域。

4) 发送函数:它与dev->hard_start_xmit()连接,在内核想通过设备传送数据时调用它。如果发送成功,hard_start_xmit()方法里释放sk_buff,返回0,否则返回1。如果dev->tbusy置为非0,则系统认为硬件忙,要等到dev->tbusy置0后才会再次发送;也可以不置dev->tbusy为非0,这样系统会不断尝试重发。tbusy的置0任务一般由中断完成,然后用mark_bh()调用通知系统可以再次发送。

5) 接收函数:它把数据从硬件移出,放在sk_buff结构中,执行netif_rx(sk_buff)告诉内核数据所在位置。真正的处理是在中断返回之后,这样可以减少中断时间。在协议层,接收数据包的流程控制分两个层次:首先,netif_rx()函数限制了从物理层到协议层的数据帧的数量;然后,每一个套接字都有一个队列,限制从协议层到套接字层的数据帧的数量。

6) 中断处理函数:需要了解相关的中断状态位以进行相应的操作。

7) 其他函数。



第九章 USB驱动程序开发

1、 OHCI简介:

   OHCI规范定义了两个主机控制器(HC)与主机控制器驱动(HDC)的通信通道(Communication Channel)。第一个为主机控制器操作寄存器,第二个为主机控制器通信域(Host Controller Communications Area, HCCA)。

   OHCI规范支持USB四种数据通信方式,并根据数据传输特定,将中断数据传输和等时数据传输归为同一类周期性数据传输方式。在HCCA中定义了4个链表。其中除完成数据链表外,其他的周期性数据链表、控制传输数据链表和批量传输数据链表都是二维链表。每个ED(Endpoint Descriptor)描述USB设备的一个端点的所有的数据传输,所有的ED被连接在一起,而TD(Transfer Descriptor)描述的才是最终要在USB总线上传输的数据包。属于同一个USB设备的端点的TD被连接在一起,并挂在相应的ED上。

   主机控制器硬件通过寄存器访问该链表来得到相关的USB传输数据包,并将其发送到USB总线上。主机控制器驱动程序则根据实际的数据传输需要,将要发送的数据包添加到相应的链表上。

   OHCI定义了两类TD:通用TD(General TD)和等时TD(Isochronous TD)。通用TD被用来支持USB中断、批量和控制三类传输方式,而等时TD被用来支持USB等时数据传输。用一个单独类型的TD来实现USB等时数据传输的目的是为了方便实现DMA数据传输功能。

2、 Linux下USB系统文件节点:同其他外设一样,上层应用软件对连接在系统地USB设备访问是通过文件系统的形式进行的。每个连接到系统总线上的USB设备可以同时对应有一个或者多个驱动程序。即一个USB设备可以在Linux系统上形成一个或多个设备节点,以供应用程序使用。在Linux系统上,每个设备节点都有其相关的主设备号和次设备号。

3、 USB主机驱动结构:Linux USB主机驱动由三部分组成:

1) USB主机控制器驱动(HCD):是USB主机驱动程序中直接与硬件交互的软件模块,其主要功能有:主机控制器硬件初始化;为USBD层提供相应的接口函数;提供根HUB(ROOT HUB)设备配置、控制功能;完成4种类型的数据传输等。

2) USB驱动(USBD):是整个USB主机驱动的核心,其主要实现的功能有:USB总线管理、USB总线设备、USB总线带宽管理、USB的4种类型数据传输、USB HUB驱动、为USB设备类驱动提供相关接口、提供应用程序访问的USB系统的文件接口等。

3) USB设备类驱动:是最终与应用程序交互的软件模块,其主要实现的功能有:访问特定的USB设备、为应用程序提供访问接口等。

   应用程序首先通过文件系统(POSIX)接口来访问相应的USB设备类驱动程序和USBD;USB设备类驱动程序则通过USBD提供的相关接口将数据请求包传递给USBD;USBD通过HCD提供的接口,进一步将数据包传递给HCD;HCD最终将数据发送到USB总线上。Linux定义了通用的数据结构URB用来在USB设备类驱动和USBD,USBD和HCD间进行数据传输。统一的URB(Universal Request Block)结构为usb主机驱动程序的开发带来了很大方便。

4、 USB时序:

1) 数据传输时序:在USB总线上,所有的数据传输都是由USB HOST发起的。每个USB设备通过地址过滤出自己要接受的数据包,并根据数据包请求的类型与USB HOST进行数据传输。由于数据传输的时序和总线带宽问题,当应用程序通过设备类提供一个URB时,该数据包并不能立即被送到USB总线上,而只能在USB总线上有足够带宽的情况下,该数据请求才会被传输。因而,HCD层为不同类型的数据传输维护了相应的数据链,当数据链上的数据包传输结束后,HCD通过调用与该数据包相关联的回调函数来通知设备类驱动程序。

2) 设备连接:当一个USB设备连接到USB总线上时,USB HUB驱动程序首先通过中断数据传输获得设备连接信息,然后通过调用USB内核模块所提供的相关函数来完成对USB设备的配置工作。同时USBD不但要为新设备分配在USBD层所需要的资源,同时也要为USB设备分配在HCD层所需要的资源。接着,USBD通过调用所有USB设备类驱动程序提供的Probe函数来查找适合该USB设备的驱动程序。

3) 设备断开:当一个USB设备断开时,USB HUB驱动程序首先通过中断数据传输获得设备断开信息,然后通过调用USB内核模块所提供的相关函数来释放USBD层和HCD层为该设备分配资源。同时通过调用该设备的相关驱动程序提供的Disconnect函数来通知设备驱动程序该设备已经断开。



第十章 图形用户接口

1、 嵌入式系统中几种流行的GUI:

1) MicroWindows;

2) MiniGUI:是我国为数不多的在国际比较知名的自由软件之一。几乎所有的MiniGUI代码都采用C语言开发,提供了完备的多窗口机制和消息传递机制以及众多空间和其他GUI元素。其引人注目的特性和技术创新主要有:

* 是一个轻量级的图形系统;

* 完善的对中日韩文字、输入法的多字体和多字符集支持

* 提供图形抽象层(GAL)以及输入抽象层(IAL)以适应嵌入式系统各种显示和输入设备

* 提供MiniGUI-Threads、MiniGUI-Lite、MiniGUI-standone三种不同架构的版本以满足不同的嵌入式系统

* 提供了丰富的应用软件,其商业版本提供了手机、PDA类产品、媒体及机顶盒类产品以及工业控制方面的诸多程序;

3) Qt/Embedded:是挪威Trolltech软件公司的产品,Linux桌面系统的KDE就是基于Qt库(不是QtE)开发的。使用QtE苦,开发者可以:

* 当移植QtE程序到不同平台时,只需要重新编译代码,而不需要对代码进行修改;

* 随意设置程序界面的外观;

* 方便地为程序连接数据库;

* 使程序本地化;

* 将程序与Java集成

同Qt一样,QtE也是用C++写的,虽然这样会增加系统资源消耗,但是却为开发者提供了清晰的程序框架,使开发者能够迅速上手,并且可以方便的编写自定义的用户界面程序。



2、 MiniGUI编程:

  它采用类似WINDOWS SDK的窗口和事件驱动机制,MiniGUI的存储空间占用情况如下:

项目

容量

备注

Linux内核

300~500KB

由系统决定

MiniGUI支持库

500~700KB

由编译选项确定

MiniGUI字体、位图等资源

400KB

由应用程序确定,可缩小到200KB以内

GB2312输入法码表

200KB

不是必需的,由应用程序确定

应用程序

1~2MB

由应用程序决定

  

  MiniGUI层次:

FrameWork, MMI, Key Apps

MiniGUI

ANSIC Library

Portable Layer



Devices

Linux/uCLinux, eCos, uC/OS-II, VxWorks, Psos

ix86, ARM, MIPS, PowerPC, M68K

  MiniGUI是一个典型的消息驱动的GUI系统,每一个MiniGUI程序都从MiniGUIMain函数开始。应用程序先以CreatMainWindow函数创建一个主窗口,由于窗口创建的时候默认是不可见的,所以我们通过ShowWindow函数显现该窗口,最后通过GetMessage(&Msg, hMainWnd)进入消息循环。

3、 Qt/Embedded编程:

  Qt是以工具开发包的形式提供给开发者的,这些工具开发包包括了图形设计器、Makefile制作工具、字体国际化工具和Qr的C++类库等。如果不考虑X窗口系统的需要,基于QrE的应用程序可以直接对缓冲帧进行写操作。QtE提供了大约200个可配置的特征,由此再Intel X86平台上库的大小范围为700KB~5MB。大部分客户选择的配置使得库的大小为1.5~4MB。Qt/Embedded与Qt/X11的Linux版本架构比较如下:

应用源代码

Qt API

Qt/Embedded

Qt/X11



Qt/XLib



X Window sever

帧缓冲

Linux内核

  信号与插槽机制提供了对象间的通信机制。Qt的窗口在事件发生后会激发信号,程序员通过建立一个函数(称作插槽)然后调用connect()函数把这个插槽和一个信号连接起来,这样就完成了一个事件和响应代码的连接。信号与插槽机制不需要类之间互相知道细节,这样就可以相对容易地开发出代码可高度重用的类。信号与插槽机制是类型安全的,它以警告的方式报告类型错误,而不会使系统产生崩溃。

  Qt拥有丰富的满足不同需求的窗体(如按钮、滚动条等)。窗体是QWidget类或它子类的实例,客户自己的窗体类需要从QWidget的子类继承。一个窗体可以包含任意数量的子窗体,子窗体可以显示在父窗体的客户区,一个没有父窗体的窗体称为顶级窗体(一个“窗口”),一个窗体通常有一个边框和标题栏作为装饰。在父窗体无效、隐藏或被删除后,它的子窗体都会进行同样的操作。



第十一章系统设计开发

1、 按照嵌入式系统的工程设计方法,嵌入式系统的设计可以分成7个阶段:产品定义、硬件与软件划分、迭代与实现、详细的硬件与软件设计、硬件与软件集成、接受测试和维护与升级。前三个阶段确定要解决的问题及需要完成的目标,也常被称为“需求阶段”;第四阶段主要解决如何在给定的约束条件下完成用户的需求;后三个阶段主要解决如何在所选择的硬件和软件基础上进行整个软/硬件系统的协调实现。

2、 硬件设计主要有以下五个关键步骤:

1) 功能定义;

2) 原理图设计:应尽量做到标准化、通用化、模块化、可扩展化;

3) PCB设计:是硬件设计的难点;

4) 硬件调试;

5) 产品化调整:一个系统的设计样机到产品化是个漫长的过程,单从硬件角度讲,至少要满足功能性、稳定性、可靠性、工艺性等最低要求。

3、 原理图设计中的几点建议:

1) 开关电源和线性电源的优缺点:



优点

缺点

开关电源

* 输入电压范围宽

* 效率高

* 输出功率大

* 应用比较灵活

* 电路相对复杂,外围器件较多

* 对电容电感的要求很高,布线也很讲究

* 开关频率会给系统带来干扰

* 纹波比较难控制

线性电源

* 电路简单,外围器件很少

* 输出精度高,有很好的负载曲线

* 工作在低频状态,不会给系统带来麻烦

* 输入范围比较受限制

* 效率低,这是由于线性电源自身的损耗造成的

* 输出功率相对较小

2) NAND和NOR Flash的速度差异:

* NOR得读速度比NAND稍快一些;

* NAND的写入速度比NOR快很多;

* NAND的4ms擦除速度远比NOR的5s快;

* 大多数写入操作需要先进行擦除操作;

* NAND的擦除单元更小,相应的擦除电路更少。

4、 PCB设计要点:

1) 元件封装的准备:

* 尽量调用标准封装库中的文件;

* 严密按照所选器件的数据手册上的规范制作封装,不能忽略累计误差;

* 注意二极管、三极管等极性元件及一些非对称元件的引脚定义不能搞错。

2) 合理布局:

* 尽量依照参考板的模式进行布局;

* 模块化布局;

* 要求模拟电路与数字电路分开;

* 输入模块与输出模块隔离;

* 去隅电容尽量靠近元件的电源/地;

* 电源等发热元件要考虑散热,主发热元件靠近出风口,大体积元件的放置避开风路;

* 元件分布均匀,避免电流过于密集;

* 板上的跳线或按键考虑易操作性;

* 元件的排列尽量整齐美观;

* 考虑机械尺寸,不要超过结构所允许的范围。

3) PCB分层:

* 如果有参考板,按照参考板进行分层;

* 多层板安排:顶层和底层为元件面,第二层为地平面,倒数第二层为电源层;

* 在不影响性能的情况下,减少PCB层数,降低成本。

4) 电源考虑:

* 系统电源入口做高频和低频滤波处理;

* 功率较高的器件配备大容量电容去除低频干扰;

* 每个器件配备0.1Uf电容过滤高频干扰;

* 高频器件电源管脚和电容之间串联磁珠达到更好的效果;

* 去耦电容的引线不能过长,特别是高频旁路电容不能带引线。

5) 时钟考虑:

* 时钟电路尽量靠近芯片;

* 晶体下方不要走线;

* 晶体外科接地,增加抗电磁干扰能力;

* 频率大于20MHz的时钟信号有地线护送;

* 时钟线宽大于10mil;

* 时钟输出端串联22~220Ω的阻尼电阻。

6) 高速信号:

* 采用手工布线;

* 高速总线走线尽量等长,并且在靠近数据输出端串联22~300Ω的阻尼电阻;

* 高速信号远离时钟芯片和晶体;

* 高速信号远离外部输入输出端口,或地线隔离。

7) 差分信号:

* 差分信号要平行等长;

* 信号之间不能走其他信号线;

* 信号要求在同一层上。

8) 走线规范:

* 不同层的信号垂直走线;

* 地线和电源层不要走线,否则要保证平面的完整性;

* 导线宽度不要突变;

* 导线变向时导角要大于90度;

* 定位孔周围0.5mm范围不要走线。

5、 硬件调试:

* 优先调试电源:保证系统可靠地供电;

* 分模块调试:可以分清模块间的问题,不至于混淆;

* 结合软件调试:对于复杂的接口,单纯硬件角度不易调试,结合软件从不同的角度测试,能起到更好的效果。

* 正确、合理的使用示波器,提高工作效率;

* 对比调试:有条件用评估板或功能相似的电路板作参考,比较差异并找出问题所在;

* 系统时钟受干扰或晶体震荡不正常导致系统工作故障;

* 复位不可靠,造成个单元未进入预期状态而出现问题;

* 因焊接问题引发的各种问题,如方向焊错、虚焊、错焊等;

* 因时序不匹配引发的通信故障,如时钟信号通过逻辑器件后产生延时,与读写信号时序搭配不上导致读写错误。

6、 嵌入式文件系统:

目前支持闪存的文件系统技术有以下几种:

* JFFS2和Yaffs。这些文件系统可以使用在没有初始化的NAND Flash和有CFI接口的NOR Flash中。JFFS2的特点包括:

* 支持数据压缩;

* 提供了“写平衡”支持;

* 支持多种结点类型;

* 提高了对闪存的利用率,降低了闪存的消耗。

  JFFS2中最重要的数据结构是jffs2_sb_info,这个数据结构用来管理所有的结点链表和闪存块。它在/src/include/Linux/jffs2_fs_sb.h中定义。

  Yaffs/Yaffs2(Yet Another Flash File System)和JFFS相比,它减少了一些功能,因此速度更快、占用内存更少。

* TrueFFS。该文件系统相当于Linux中的MTD层,必须配合其他文件系统。

* FTL/NTFL。它是一种中间层解决方案的统称,为上层文件系统提供接口。

* RAMFS、CRAMFS和ROMFS。这些文件系统用于早期的小容量闪存设备,系统功能比较简单,仅提供基本接口,只属于只读的闪存文件系统。适合存储空间小的系统。

7、 MTD简介:

无论JFFS2还是Yaffs,都需要MTD(Memory Technology Devices,内存技术设备)的支持。MTD是对Flash操作的接口,提供了一系列的标准函数,将硬件驱动设计和系统程序设计分开,硬件驱动人员不用了解存储设备的组织方法,只需提供标准的函数调用,如读、写等。

一个MTD原始设备可以通过mtd_part分割成数个MTD原始设备注册进mtd_table,mtd_table中的每个MTD原始设备都可以被注册成一个MTD设备,

Logo

更多推荐