ARM & linux 嵌入式系统实验教程.pdf
双实科技 Linux 实验指导教材 第 1 篇 嵌入式 Linux 开发基础知识 .............................................................................................5 1.1 嵌入式 Linux 简介 ...........................................................................................................5 1.2 嵌入式 Linux 开发平台简介............................................................................................7 1.2.1 概述..........................................................................................................................7 1.2.2 功能描述..................................................................................................................9 1.4 建立嵌入式 Linux 开发环境..........................................................................................17 1.4.1 RedHat linux 的安装...............................................................................................17 1.4.2 开发环境的配置(NFS) ......................................................................................30 第二篇 开发环境与开发工具的熟悉..............................................................................................36 2.1 Linux 基础命令 ................................................................................................................36 1、 实验目的............................................................................................................36 2、 实验设备............................................................................................................36 3、 实验原理............................................................................................................36 4、 实验步骤............................................................................................................38 2.2 Linux 下编辑器 VI 的操作 ..............................................................................................43 1、 实验目的............................................................................................................43 2、 实验设备............................................................................................................43 3、 实验原理............................................................................................................43 4、 实验步骤............................................................................................................47 2.3 Minicom 实验 ..................................................................................................................49 1、 实验目的............................................................................................................49 2、 实验设备............................................................................................................49 3、 实验原理............................................................................................................49 4、 实验步骤............................................................................................................49 2.4 Gcc 编译器.....................................................................................................................53 1、 实验目的............................................................................................................53 2、 实验设备............................................................................................................53 3、 实验原理............................................................................................................53 4、 实验步骤............................................................................................................58 2.5 GDB 调试器.......................................................................................................................61 1、 实验目的..........................................................................................................61 2、 实验设备..........................................................................................................61 3、 实验原理..........................................................................................................61 4. 实验步骤.........................................................................................................64 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 1 页 共 175 页 双实科技 2.6 交叉编译器的安装..........................................................................................................70 1、 实验目的............................................................................................................70 2、 实验设备............................................................................................................70 3、 实验原理............................................................................................................70 4、 实验步骤............................................................................................................71 2.7 Linux 下的 Makefile ...................................................................................................74 1、 实验目的............................................................................................................74 2、 实验设备............................................................................................................74 3、 实验原理............................................................................................................74 4、 实验步骤............................................................................................................80 2.8 通过 JTAG 口下载映像到开发板....................................................................................84 1、 实验目的............................................................................................................84 2、 实验设备............................................................................................................84 3、 实验原理............................................................................................................84 4、 实验步骤............................................................................................................88 第三篇 构建嵌入式系统..................................................................................................................90 3.1 编译 BootLoader(uboot) ..............................................................................................90 1、 实验目的............................................................................................................90 2、 实验设备............................................................................................................90 3、 实验原理............................................................................................................90 3.1. Bootloader 介绍...............................................................................................90 3.2. Bootloader 的启动...........................................................................................90 3.3. Bootloader 的种类...........................................................................................93 3.4. U-Boot 源码结构...............................................................................................94 4、 实验步骤............................................................................................................95 3.2 编译嵌入式 Linux 内核................................................................................................100 1、 实验目的..........................................................................................................100 2、 实验设备..........................................................................................................100 3、 实验原理..........................................................................................................100 4、 实验步骤..........................................................................................................103 3.3 构建嵌入式 Linux 文件系统........................................................................................107 1、 实验目的..........................................................................................................107 2、 实验设备..........................................................................................................107 3、 实验原理..........................................................................................................107 4、 实验步骤..........................................................................................................110 3.4 制作和烧写 Cramfs 文件系统......................................................................................118 1、 实验目的..........................................................................................................118 2、 实验设备..........................................................................................................118 3、 实验原理..........................................................................................................118 4、 实验步骤..........................................................................................................120 第四篇 Linux 应用编程实验 ........................................................................................................128 4.1 多线程应用程序设计......................................................................................................128 1、 实验目的..........................................................................................................128 2、 实验内容..........................................................................................................128 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 2 页 共 175 页 双实科技 3、 预备知识..........................................................................................................128 4、 实验设备..........................................................................................................128 5、 实验原理..........................................................................................................128 6、 实验步骤..........................................................................................................131 7、 思考题..............................................................................................................134 4.2 串口端口应用程序设计..................................................................................................135 1、 实验目的..........................................................................................................135 2、 实验内容..........................................................................................................135 3、 预备知识..........................................................................................................135 4、 实验设备..........................................................................................................135 5、 实验原理..........................................................................................................135 6、 实验步骤..........................................................................................................138 7、 思考题..............................................................................................................141 4.4 GPRS 通信实验 ................................................................................................................142 1、 实验目的..........................................................................................................142 2、 实验内容..........................................................................................................142 3、 预备知识..........................................................................................................142 4、 实验设备..........................................................................................................142 5、 实验原理..........................................................................................................142 6、 实验步骤..........................................................................................................149 7、 思考题..............................................................................................................149 第五篇 Linux 驱动模块实验 ........................................................................................................150 5.1 内核驱动设计入门—模块方式驱动..............................................................................150 1、 实验目的..........................................................................................................150 2、 实验内容..........................................................................................................150 3、 预备知识..........................................................................................................150 4、 实验设备..........................................................................................................150 5、 实验原理..........................................................................................................150 6、 实验步骤..........................................................................................................161 7、 思考题..............................................................................................................161 5.2 系统中断实验—键盘中断的实现..................................................................................162 1、 实验目的..........................................................................................................162 2、 实验内容..........................................................................................................162 3、 预备知识..........................................................................................................162 4、 实验设备..........................................................................................................162 5、 实验原理..........................................................................................................162 6、 实验步骤..........................................................................................................166 7、 思考题..............................................................................................................166 5.3 CAN 驱动的实现............................................................................................................167 1、 实验目的..........................................................................................................167 2、 实验内容..........................................................................................................167 3、 预备知识..........................................................................................................167 4、 实验设备..........................................................................................................167 5、 实验原理..........................................................................................................167 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 3 页 共 175 页 双实科技 6、 实验步骤..........................................................................................................170 7、 思考题..............................................................................................................170 5.4 SD 驱动使用实验 ............................................................................................................172 1、 实验目的..........................................................................................................172 2、 实验内容..........................................................................................................172 3、 预备知识..........................................................................................................172 4、 实验设备..........................................................................................................172 5、 实验原理..........................................................................................................172 5.1. SD 记忆卡系统概念........................................................................................172 5.2. 总线拓扑..........................................................................................................172 5.3. SD 总线............................................................................................................173 5.4. SD 记忆卡 – 引脚和寄存器........................................................................173 5.5. SD 卡的硬件连接图.........................................................................................174 6、 实验步骤..........................................................................................................175 7、 思考题..............................................................................................................175 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 4 页 共 175 页 双实科技 第1篇 嵌入式 Linux 开发基础知识 1.1 嵌入式 Linux 简介 随着微处理器的产生,价格低廉、结构小巧的 CPU 和外设连接提供了稳定可靠的硬件架 构,那么限制嵌入式系统发展的瓶颈就突出表现在了软件方面。尽管从八十年代末开始,陆 续出现了一些嵌入式操作系统,比较著名的有 Vxwork、pSOS、Neculeus 和 Windows CE。但这 些专用操作系统都是商业化产品,其高昂的价格使许多低端产品的小公司望而却步;而且, 源代码封闭性也大大限制了开发者的积极性。另外,结合国内实情,当前国家对自主操作系 统的大力支持,也为源码开放的 LINUX 的推广提供的广阔的发展前景。还有,对上层应用开 发者而言,嵌入式系统需要的是一套高度简练、界面友善、质量可靠、应用广泛、易开发、 多任务,并且价格低廉的操作系统。在不久的将来,从冰箱到收音机都会内置处理器。因为 Linux 的开放性,许多人认为 Linux 非常适合多数 Internet 设备。他们认为 Linux 可以支持 不同的设备,支持不同的配置。Linux 对厂商不偏不倚而且成本极低,能够很快成为用于各种 设备的操作系统。如今,业界已经达成共识:即嵌入式 linux 是大势所趋,其巨大的市场潜 力与酝酿的无限商机必然会吸引众多的厂商进入这一领域。 嵌入式操作系统主要有 Palm OS,Windows CE,EPOC,LinuxCE,QNX,ECOS,LYNX,高端嵌 入式系统要求许多高级的功能,如图形用户界面和网络支持 。很多高端 RTOS 供应商已经提 供了这些功能,但其价格也很高端,一般人难以接受。微软的 Windows CE 也有此类功能,却 不具备大多数嵌入式系统要求的实时性能,而且难以移植,也曾经有人想以 DOS 为基础用单 独的第三方工具拼凑一个系统,但这种努力将是白费。现在需要的是一个便宜、成熟并且提 供高端嵌入式系统所必须特性的操作系统,嵌入式 Linux 操作系统以价格低廉、功能强大又 易于移植而正在被广泛采用,成为新兴的力量,所以,众多商家纷纷转向了嵌入式 linux。 Linux 为嵌入操作系统提供了一个极有吸引力的选择,它是个和 Unix 相似、以核心为基 础的、完全内存保护、多任务多进程的操作系统。支持广泛的计算机硬件,包括 X86,Alpha,Sparc,MIPS,PPC,ARM,NEC,MOTOROLA 等现有的大部分蕊片。程式源码全部公开,任 何人可以修改并在 GNU 通用公共许可证(GNU General Public License)下发行,这样,开发人 员可以对操作系统进行定制,再也不必担心像 MS windows 操作系统中"后门"的威胁。同时由 于有 GPL 的控制,大家开发的东西大都相互兼容,不会走向分裂之路。Linux 用户遇到问题时 可以通过 Internet 向网上成千上万的 Linux 开发者请教,这使最困难的问题也有办法解决。 Linux 带有 Unix 用户熟悉的完善的开发工具,几乎所有的 Unix 系统的应用软件都已移植到了 Linux 上。Linux 还提供了强大的网络功能,有多种可选择窗口管理器(X windows)。其强大 的语言编译器 gcc、g++等也可以很容易得到。不但成熟完善、而且使用方便。 ★选择 linux 的原因 ◆可应用于多种硬件平台。Linux 已经被移植到多种硬件平台,这对受开销、时间限制的 研究与开发项目是很有吸引力的。原型可以在标准平台上开发然后移植到具体的硬件上,加 快了软件与硬件的开发过程。 ◆Linux 可以随意地配置不需要任何的许可证或商家的合作关系。 ◆它是免费的,源代码可以得到。这是最吸引人的。毫无疑问,这会节省大量的开发费 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 5 页 共 175 页 双实科技 用。 ◆它本身内置网络支持。 ◆Linux 的高度模块化使添加部件非常容易。 ◆Linux 在台式机上的成功,使大家看到了 linux 在嵌入式系统中的辉煌前 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 6 页 共 175 页 双实科技 1.2 嵌入式 Linux 开发平台简介 Sinosys-EP8347 嵌入式处理器平台是一种针对网络存贮市场设计的高性能主板。该主板 基于 Freescale 的 MPC8347E 进行设计,具有高性能、低功耗的特点。CPU 主频可达 667MHz。 主板上集成了可扩展到 256MB 的 DDR SDRAM 和可以扩展到 16MB 的 FLASH 存储器。 Sinosys-EP8347 带有丰富的外围接口:2 个独立的 1000/100/10 以太网接口,2 个 RS232 接口,1 个 3.3V 的 PCI 接口,4 个 SATA 接口,1 个 USB 接口和 1 个扩展总线接口。MPC8347 SATA SBC 内嵌了强大的安全处理器。很多典型的加解密算法都可以通过硬件完成,对于网络 安全应用来说,这是一个很好的帮助。您可以使用套件提供 的各种开发工具按照自己的意图或需要设计各种各样的应用程序,而我们也提供了很多精彩 的应用制作实例供您参考,并配备了完善的实验设计指导手册。 1.2.1 概述 a) ARM9-M31 开发板硬件特性 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 7 页 共 175 页 双实科技 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 8 页 共 175 页 双实科技 1.2.2 功能描述 本节描述 SinoSys-M31 功能方面的特性。下图为 SinoSys-M31 内在架构。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 9 页 共 175 页 双实科技 b) ARM920T S3C2440A CPU ARM920T 核由 ARM9TDMI、存储管理单元(MMU)和高速缓存三部分组成。其中,MMU 可以管理虚拟内存,高速缓存由独立的 16KB 地址和 16KB 数据高速 Cache 组成。ARM920T 有 两个内部协处理器:CPl4 和 CPl5。CPl4 用于调试控制,CPl5 用于存储系统控制以及测试控 制。 S3C2440A 的片上资源包括: ·1 个 LCD 控制器(支持 STN 和 TFT 的液晶显示屏) ·32K 的 Cache ·SDRAM 控制器 ·3 个通道的 UART ·4 个通道的 DMA ·2 通道 SPI ·AC97 解码接口 ·RTC 模块 ·4 个具有 PWM 功能的计时器和 1 个内部时钟 ·8 通道的 10 位 ADC ·触摸屏接口 ·I2C 总线接口 ·I2S 总线接口 ·2 个 USB 主机接口,1 个 USB 设备接口 ·2 个 SPI 接口 ·SD 接口和 MMC 卡接口 ·看门狗计数器 ·117 位通用 I/O 口和 24 位外部中断源 ·8 通道 10 位 AD 控制器 ·摄像头接口 c) Memory Map 下表是SinoSys-M31 的内存分布表。该表说明了系统外设的片选空间。 (1) 不使用NAND FLASH 启动,16MB NOR FLASH 与CS0 连接。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 10 页 共 175 页 双实科技 (2) 使用NAND FLASH 启动,16MB NOR FLASH 与CS1 连接 d) 时钟资源 在时钟方面S3C2440A 有着突出的特点,该芯片集成了一个具有日历功能的RTC 和具有 PLL(MPLL 和UPLL)的芯片时钟发生器。MPLL 产生主时钟,能够使处理器工作频率最高达到 400MHz。这个工作频率能够使处理器轻松运行于Windows CE、Linux 等操作系统以及进行较 为复杂的信息处理。UPLL 产生实现主从USB 功能的时钟。下表描述了控制引脚OM2 和OM3 的组合与时钟操作模式之间的关系。本系统采用OM[3:2]=00,EXTCLK=VDD 的操作模式。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 11 页 共 175 页 双实科技 e) 引导方式 S3C2440X 支持从NAND FLASH 启动,NAND FLASH 具有容量大、比NOR FLASH 价 格低等特点。系统采用NAND FLASH 与SDRAM 组合,可以获得非常高的性价比。 用户可以将引导代码和操作系统镜像存放在外部的NAND FLASH 中,并从NAND FLASH 启动。当处理器在这种模式下上电复位时,内置的NAND FLASH 将访问控制接口, 并将引导代码自动加载到内部SRAM(此时该SRAM 定位于起始地址空间0x00000000,容量 为4KB)并且运行。之后,SRAM 中的引导程序将操作系统镜像加载到SDRAM 中,操作系 统就能够在SDRAM 中运行。启动完毕后,4KB 的启动SRAM 就可以用于其他用途。如果 从其他方式启动,启动ROM 就要定位于内存的起始地址空间0x00000000,处理器直接在ROM 上运行启动程序,而4KB 启动SRAM 被定位于内存地址的0x40000000 处。 f) 中断分配 S3C2440X 的中断控制器能接收来自56 个中断源的请求。这些中断源由内部的外围设 备提供(如DMA 控制器、UART 等)。下表S3C2440X 的中断源: 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 12 页 共 175 页 双实科技 本系统的外部中断分配 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 13 页 共 175 页 双实科技 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 14 页 共 175 页 双实科技 1.3 嵌入式 Linux 开发流程简介 在一个嵌入式系统中使用 Linux 开发,根据应用需求的不同有不同的配置开发方法,但 是一般都要经过如下的过程: a) 建立开发环境 操作系统一般使用 RedHat-Linux,版本从 7 到 9 都可以,选择定制安装或全部安装,通 过网络下载相应的 GCC 交叉编译器进行安装(例如 arm-Linux-gcc、arm-μclibc-gcc),或者 安装产品厂家提供的交叉编译器。 b) 配置开发主机 配置 MINICOM,一般的参数为波特率为 115 200bps,数据位为 8 位,停止位为 1,无奇偶 校验,软件硬件流控设为无。在 Windows 下的超级终端的配置也是这样的。MINICOM 软件的作 用是作为调试嵌入式开发板的信息输出的监视器和键盘输入的工具。配置网络,主要是配置 NFS 网络文件系统,需要关闭防火墙,简化嵌入式网络调试环境设置过程。 c) 建立引导装载程序 BOOTLOADER 从网络上下载一些公开源代码的 BOOTLOADER,如 U-BOOT、BLOB、VIVI、LILO、ARM-BOOT、 RED-BOOT 等,根据自己具体的芯片进行移植修改。有些芯片没有内置引导装载程序,例如三 星的 ARM7、ARM9 系列芯片,这样就需要编写开发板上 Flash 的烧写程序,网络上有免费下载 的 Windows 下通过 JTAG 并口简易仿真器烧写 ARM 外围 Flash 芯片的烧写程序,也有 Linux 下 的公开源代码的 J-Flash 程序。如果不能烧写自己的开发板,就需要根据自己的具体电路进 行源代码修改。这是系统正常运行的第一步。如果购买了厂家的仿真器当然比较容易烧写 Flash,这对于需要迅速开发自己产品的人来说可以极大地提高开发速度,但是其中的核心技 术是无法了解的。 d) 下载别人已经移植好的 Linux 操作系统 如μCLinux、ARM-Linux、PPC-Linux 等,如果有专门针对所使用的 CPU 移植好的 Linux 操作系统那是再好不过的,下载后再添加自己的特定硬件的驱动程序,进行调试修改,对于 带 MMU 的 CPU 可以使用模块方式调试驱动,对于μCLinux 这样的系统则需编译进内核进行调 试。 e) 建立根文件系统 从 www.busybox.net 下载使用 BUSYBOX 软件进行功能裁减,产生一个最基本的根文件系 统,再根据自己的应用需要添加其他程序。默认的启动脚本一般都不会符合应用的需要,所 以 就 要 修 改 根 文 件 系 统 中 的 启 动 脚 本 , 它 的 存 放 位 置 位 于 /etc 目 录 下 , 包 括 : /etc/init.d/rc.S 、 /etc/profile 、 /etc/.profile 等 , 自 动 挂 装 文 件 系 统 的 配 置 文 件 /etc/fstab,具体情况会随系统不同而不同。根文件系统在嵌入式系统中一般设为只读,需 要使用 mkcramfs、genromfs 等工具产生烧写映像文件。 f) 建立应用程序的 Flash 磁盘分区 一般使用 JFFS2 或 YAFFS 文件系统,这需要在内核中提供这些文件系统的驱动,有的系 统使用一个线性 Flash(NOR 型)512KB~32MB,有的系统使用非线性 Flash(NAND 型)8~512MB, 有的两个同时使用,需要根据应用规划 Flash 的分区方案。 g) 开发应用程序 应用程序可以放入根文件系统中,也可以放入 YAFFS、JFFS2 文件系统中,有的应用不使 用根文件系统,直接将应用程序和内核设计在一起,这有点类似于μCOS-II 的方式。 h) 烧写内核、根文件系统、应用程序 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 15 页 共 175 页 双实科技 i) 发布产品 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 16 页 共 175 页 双实科技 1.4 建立嵌入式 Linux 开发环境 嵌入式 Linux 开发环境有以下几个方案: 1. 基于 PC 机的 Windows 操作系统下的 cygwin。 2. 在 Windows 下安装虚拟机后,再在虚拟机中安装 Linux 操作系统. 3. 直接安装 Linux 操作系统. 由于基于 Windows 环境要么有兼容性问题,要么速度有影响,所以推荐读者使用纯 Linux 操作系统环境。我们实际的开发环境为 RedHat9.0,它已经支持中文,并且包含了绝大 部分的开发工具,不用担心装了 Linux 就能使用 Windows 问题,一般情况都是用户已经有了 Windows 操作系统,再安装 Linux,Linux 会自动安装一个叫做 GRUB 的启动引导软件,可以 选择引导多个操作系统。 1.4.1 RedHat linux 的安装 简单地说,Linux 是一套免费使用和自由传播的类 Unix 操作系统,是一个基于 POSIX 和 UNIX 的多用户、多任务、支持多线程和多 CPU 的操作系统。它能运行主要的 UNIX 工具软件、 应用程序和网络协议。它支持 32 位和 64 位硬件。Linux 继承了 Unix 以网络为核心的设计 思想,是一个性能稳定的多用户网络操作系统。它主要用于基于 Intel x86 系列 CPU 的计算 机上。这个系统是由全世界各地的成千上万的程序员设计和实现的。其目的是建立不受任何 商品化软件的版权制约的、全世界都能自由使用的 Unix 兼容产品! Linux 以它的高效性和灵活性著称。Linux 模块化的设计结构,使得它既能在价格昂贵 的工作站上运行,也能够在廉价的 PC 机上实现全部的 Unix 特性,具有多任务、多用户的能 力。Linux 是在 GNU 公共许可权限下免费获得的,是一个符合 POSIX 标准的操作系统。Linux 操作系统软件包不仅包括完整的 Linux 操作系统,而且还包括了文本编辑器、高级语言编译 器等应用软件。它还包括带有多个窗口管理器的 X-Windows 图形用户界面,如同我们使用 Windows NT 一样,允许我们使用窗口、图标和菜单对系统进行操作。 Linux 具有 Unix 的优点:稳定、可靠、安全,有强大的网络功能。在相关软件的支持下, 可实现 WWW、FTP、DNS、DHCP、E-mail 等服务,还可作为路由器使用,利用 ipchains/iptables 可构建 NAT 及功能全面的防火墙。 Linux 有很多发行版本,较流行的有:RedHat Linux、Debian Linux、RedFlag Linux 等。 RedHat Linux,支持 Intel,Alpha 和 SPARC 平台,具有丰富的软件包。可以说,RedHat Linux 是 Linux 世界中非常容易使用的版本,它操作简单,配置快捷,独有的 RPM 模块功能 使得软件的安装非常方便. g) RedHat Linux9.0 的安装 在开始安装Linux 之前,请首先收集一下相关硬件信息。如果不能确定系统对硬件的兼 容性可以到http://hardware.redhat.com 进行查询。为Linux 准备一个5G 以上空间(建议 值)大小的分区。如果使用VM Ware 的话,相关的设置请查看网上相关的教程。然后就可以 开始我们的Linux 安装之旅了。 第一步 首先我们准备好三张安装光盘,用第一张光盘引导计算机。从光盘启动后会出现如图1 所示画面,这是一个提示符状态,可以通过输入不同的命令来选择不同的安装模式。1.图形 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 17 页 共 175 页 双实科技 安装(直接回车) 2.文本安装(输入 linux text)为了避免不必要的麻烦,我们直接按回 车键,用缺省模式安装。 图1 第二步 然后会询问用户是否对光盘完整性进行检查,如图2,一般来说选择"Skip"就可以。 图2 第三步 接下来就进入了Red Hat Linux 的图形安装界面如图3 所示。Red Hat Linux 的安装向导 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 18 页 共 175 页 双实科技 的智能化程度也很高,通过使用鼠标指指点点就可以完成安装。 图3 第四步 选择在整个安装过程中使用的语言如图4 所示,这里我们当然选择“Chinese(Simplified) (简体中文)”。 图4 第五步 键盘配置如图5 所示,选择"U.S. English"。(除非使用特殊键盘类型,否则不需要对键 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 19 页 共 175 页 双实科技 盘进行特殊配置。) 图5 第六步 鼠标配置如图6 所示,安装程序通常会选择正确的鼠标类型,直接单击“下一步”。 图6 第七步 选择安装类型如图7 所示,Red Hat 提供了三种不同类型的软件包套件,个人桌面,工 作站和服务器。可以根据自己的需要选择不同的安装类型。这里我们选择“定制”。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 20 页 共 175 页 双实科技 图7 第八步 硬盘分区如图8 所示。Linux 操作系统下分区划分和Windows 的不同。习惯了Windows 工作模式的朋友在这一步可能会遇到困难。但是不要害怕,下面的每一步都弄明白就可以顺 利完成分区过程。选择“用 Disk Druid 手工分区”,单击“下一步”。这里选择“自动分区” 会有破坏硬盘原有数据的可能性。 图8 第九步 开始对硬盘进行分区如图9 所示,在这里可以看到目前现有磁盘的分区情况。我们可以 通过双击空闲的磁盘空间或者点击“新建”按钮来为Linux 创建一个新的分区。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 21 页 共 175 页 双实科技 图9 第十步 我们双击空闲的磁盘分区,会出现一个添加分区的对话框如图 10 所示,在“挂载点”的 下拉列表中选择/,也就是“根挂载点”。在“文件系统类型”的下拉列表中选择 ext3,这个 是 Linux 所使用的文件系统类型。为分区指定空间大小,起始柱面不需要更改,点击终止柱 面输入框后面的上下箭头来根据需要调整分区大小。点击“确定”按钮。在整个 Linux 系统 中有且只有一个根挂载点,这个将是整个系统的根目录。Linux 并不像 Windows 和 DOS 操 作系统有很多盘符,每个盘符都有一个“根目录”。Linux 系统下的/目录永远是目录树的最 底层。 图 10 第十一步 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 22 页 共 175 页 双实科技 双击空闲空间为Linux 系统创建页面分区如图11 所示。在“文件系统类型”下拉列表中 选择swap,通过调整终止柱面来制定分区大小。点击“确定”按钮。swap 空间的大小一般为 物理内存的2-3 倍。如果不知道物理内存的具体数值,可以点击终止柱面数据框后面的上下 箭头来把“大小(MB)”后面的数值调整为512(±4),一般来说都可以满足需要。 图11 第十二步(可选) 默认情况下Linux 系统下的应用程序的是存放在/usr 目录的,如果空间充足可以为/usr 目录单独指定挂载点。如图12 所示,在“挂载点”后的下拉列表中选择/usr,其他项目设置 方法同“第九步” 图 12 第十三步 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 23 页 共 175 页 双实科技 引导装载程序设置如图13 所示。现在多系统共存已经是司空见惯了的事情了。Red Hat 提供的GRUB 工具提供了多系统启动的解决方案。直接单击下一步就可以了。 图 13 第十四步 网络配置如图14 所示,这个根据自己的网络情况进行相应配置。如果对网络不是很了解。 可以直接单击下一步跳过。 图 14 第十五步 防火墙配置如图15 所示。Red Hat 提供了三种安全级别的防火墙配置,可以根据自己的 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 24 页 共 175 页 双实科技 需要进行选择。如果作为服务器,那么需要打开提供服务使用的端口。 因为我们的Red Hat 只用于开发,因此不需要防火墙。 图 15 第十六步 附加语言支持如图16 所示,选择可能会用到的语言,以提供相关语言的显示、输入。 图 16 第十七步 设置时区如图17 所示。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 25 页 共 175 页 双实科技 图 17 第十八步 设置根口令如图18 所示。Linux 系统下有一个根用户,在系统中拥有至高无上的权利, 用户名是root。一般来说只有在对系统进行管理时才使用此用户。建议密码满足一定复杂性 要求。 图 18 第十九步 验证配置如图19 所示。如果没有特殊要求,或者不知道这个是什么。请单击下一步。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 26 页 共 175 页 双实科技 图 19 第二十步(在第七步选择“定制”的情况下) 选择软件包如图20 所示。Red Hat 为用户提供丰富的应用软件,按功能进行了分类。如 果你想编译内核或QT 时少出问题,请选择“全部”。 图 20 第二十一步 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 27 页 共 175 页 双实科技 准备开始安装如图21 所示的全部工作都做好后,就可以开始进行文件复制了。 图 21 第二十二步 安装过程中会提示更换光盘如图22 所示。 图 22 第二十三步 换第三张盘! 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 28 页 共 175 页 双实科技 图 23 第二十四步 图 24 第二十五步 完成Linux 的安装,单击退出按钮,Linux 就可以启动工作了。如图25 所示 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 29 页 共 175 页 双实科技 图 25 1.4.2 开发环境的配置(NFS) 1、 预备知识 1. 什么是 NFS ( Network FileSystem ) 我们要先来了解一下,什么是 NFS 呢?所谓的 NFS 就是 Network FileSystem 的缩写, 最早之前是由 Sun 这家公司所发展出来的。他最大的功能就是可以透过网络,让不同的机器、 不同的操作系统、可以彼此分享个别的档案 ( share file ),所以,也可以简单的将他看做是一 个 file server。这个 NFS Server 可以让你的 PC 来将网络远程的 NFS 主机分享的目录,挂 载到本地端的机器当中,所以,在本地端的机器看起来,那个远程主机的目录就好像是自己 的 partition 一般。 就如同上面的图标一样,当我们的 NFS Server 设定好了之后,其它的 Client 端就可以 直接在 Server 上面存取资料。也就是说,其它的 Personal Computer 可以“挂载 NFS server 所提供的文件或目录”,而且挂载之后,这个目录看起来就像你的本地端的磁盘区块一般,只 要权限对了,那么你可以使用 cp, cd, mv, rm... 等等磁盘或档案相关的指令。虽然 NFS 有属 于自己的协议与使用的 port number,但是在数据传送或者其它相关信息传递的时候, NFS 使 用的则是一个称为远程过程调用( Remote Procedure Call, RPC )的协议来协助 NFS 本身的运 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 30 页 共 175 页 双实科技 作。 2. 什么是 RPC ( Remote Procedure Call ) 由字面上的意思来看“远程过程调用”就是一些程序( Program )在执行远程联机时,需要 用到的程序。简单的来说,当我们在使用某些服务来进行远程联机的时候,有些信息,例如 主机的 IP、服务的 port number、与对应到的服务之 PID 等等,都需要管理与对应。这些管 理 port 的对应与服务相关性的工作,就是这个 Remote Procedure Call, RPC 的任务了。 如果我们将 NFS 与 RPC 两者的相关性连接起来的话,那么你应该就可以知道: NFS 本身 的服务并没有提供资料传递的协议,但是 NFS 却能让我们进行档案的分享,这其中的原因, 就是 NFS 使用到一些其它相关的传输协议。而这些传输的协议,就是使用到这个所谓的 RPC 的功能。这也就是说,NFS 本身就是使用 RPC 的一个 program 。同时要注意到的是,在某 些状况中,不但跑 NFS 的 Server 需要激活 RPC 的服务,连带的,要挂载 NFS partition 的 Client 机器,也需要同步激活 RPC 才行。这样 Server 端与 Client 端才能藉由 RPC 的协议 来进行 program port 的对应。 3. 服务器端的设定(以 LINUX 为例) 服务器端的设定都是在/etc/exports 这个文件中进行设定的,设定格式如下: 欲分享出去的目录 主机名称 1 或者 IP1(参数 1,参数 2) 主机名称 2 或者 IP2(参数 3,参 数 4) 上面这个格式表示,同一个目录分享给两个不同的主机,但提供给这两台主机的权限和 参数是不同的,所以分别设定两个主机得到的权限。 可以设定的参数主要有以下这些: 1. rw:可读写的权限; 2. ro:只读的权限; 3. no_root_squash:登入到 NFS 主机的用户如果是 ROOT 用户,他就拥有 ROOT 的权 限,此参数很不安全,建议不要使用。 4. root_squash:这个选项不允许 root 用户访问挂载上来的 NFS 卷。 5. all_squash:不管登陆 NFS 主机的用户是什么都会被重新设定为 nobody。 6. anonuid:将登入 NFS 主机的用户都设定成指定的 user id,此 ID 必须存在于/etc/passwd 中。 7. anongid:同 anonuid 。 8. sync:资料同步写入存储器中。 9. async:资料会先暂时存放在内存中,不会直接写入硬盘。 10. insecure:允许从这台机器过来的非授权访问。 例如可以编辑/etc/exports 为: /tmp *(rw,no_root_squash) /home/public 192.168.0.*(rw) *(ro) /home/test 192.168.0.100(rw) /home/linux *.the9.com(rw,all_squash,anonuid=40,anongid=40) 设定好后可以使用以下命令启动 NFS: /etc/rc.d/init.d/portmap start (在 REDHAT 中 PORTMAP 是默认启动的) /etc/rc.d/init.d/nfs start 4. exportfs 命令: 如果我们在启动了 NFS 之后又修改了/etc/exports,是不是还要重新启动 nfs 呢?这个时候 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 31 页 共 175 页 双实科技 我们就可以用 exportfs 命令来使改动立刻生效,该命令格式如下: exportfs [-aruv] -a :全部 mount 或者 unmount /etc/exports 中的内容 -r :重新 mount /etc/exports 中分享出来的目录 -u :umount 目录 -v :将详细的信息输出到屏幕上。 具体例子: [root @test root]# exportfs -rv (全部重新 export 一次) exporting 192.168.0.100:/home/test exporting 192.168.0.*:/home/public exporting *.the9.com:/home/linux exporting *:/home/public exporting *:/tmp reexporting 192.168.0.100:/home/test to kernel exportfs -au (全部都卸载) 客户端的操作 a) showmount 的用法。 showmount -a :这个参数是一般在 NFS SERVER 上使用,是用来显示已经 mount 上本机 nfs 目录 的 cline 机器。 -e :显示指定的 NFS SERVER 上 export 出来的目录。 例如: showmount -e 192.168.0.30 Export list for localhost: /tmp * /home/linux *.linux.org /home/public (everyone) /home/test 192.168.0.100 b) mount nfs 目录的方法: mount -t nfs hostname(orIP):/directory /mount/point 具体例子: Linux: mount -t nfs 192.168.0.1:/tmp /mnt/nfs Solaris:mount -F nfs 192.168.0.1:/tmp /mnt/nfs BSD: mount 192.168.0.1:/tmp /mnt/nfs 5. 2、 NFS 的使用 (1) 准备 首先,连接实验箱的电源,串口线,网线。然后输入下面的命令配置本机的IP。 #ifconfig eth0 10.0.0.10 (2) 修改/etc/exports 输入下面命令,修改/etc/exports 文件,把我们的工作目录/root/Myjob 公布出去。如图1 所 示。 #vi /etc/exports 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 32 页 共 175 页 双实科技 /root/Myjob 10.0.0.*(rw,no_root_squash) 图1 (3) 激活 portmap 与 nfs 服务 输入下列命令激活portmap 和nfs 服务: #/etc/rc.d/init.d/portmap start #/etc/rc.d/init.d/nfs start (4) 确认可用目录 输入下列命令确认可用目录, 如图 2 所示。 #showmount –e 10.0.0.10 图2 (5) 在本机内建立挂载点 为了确保 NFS 服务已经正确启动,在正式把实验箱和 PC 连接前,我们先在 PC 本机上进 行挂载测试。输入下面命令建立挂载点。 #mkdir /root/Myjob_NFS (6) 进行测试性挂载 输入下面的命令,进行实际的挂载。如图 3 所示。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 33 页 共 175 页 双实科技 #mount –t nfs 10.0.0.10:/root/Myjob /root/Myjob_NFS #cd /root/Myjob #ls #cd /root/Myjob_NFS #ls 图3 从上图我们可以看出,Myjob 和 Myjob_NFS 的内容完全一样。再次查看前一实验生成的 test 文件的类型为 ARM 格式。尝试在 PC 上运行这个程序会出现如图的错误,因为这并不是 PC 的程序,下面我们将会把程序放到实验箱中的 Linux 在运行。 (7) 配置实验箱的NFS客户端 a) 在确定 NFS 服务端没有问题后,现在可以在实验箱上进行实际的挂载。输入下 面命令。 #minicom 打开实验箱电源,这时,你将会在 minicom 的窗口中看到实验箱的 linux 启动的 信息,如图 4 所示。配置实验箱网口 1 的 IP #ifconfig eth0 10.0.0.11 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 34 页 共 175 页 双实科技 图4 b) 建立挂载目录 #cd /tmp #mkdir Myjob c) 进行挂载(这时最好关闭防火墙) # mount –t nfs 10.0.0.10:/root/Myjob /tmp/Myjob d) 测试上一实验生成的可执行文件 test, 如图 5 所示 #cd /tmp/Myjob #./test 图5 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 35 页 共 175 页 双实科技 第二篇 开发环境与开发工具的熟悉 2.1 Linux 基础命令 1、 实验目的 z 熟练运行 Linux 的基础命令 2、 实验设备 z 硬件:PC 机 z 软件:Red Hat9 3、 实验原理 Linux 虽然是免费的,但它的确是一个非常优秀的操作系统,与 MS-WINDOWS 相比具 有可靠、 稳定、速度快等优点,且拥有丰富的根据 UNIX 版本改进的强大功能。下面,作为一 个典型的 DOS 和 WINDOWS 用户,让我们一起来学习 Linux 的一些主要命令,希望大家能 尽快进入到 Linux 的世界里。 3.1. su su 命令是最基本的命令之一,常用于不同用户间切换。例如,如果登录为 user1,要切 换为 user2,只要用如下命令: $su user2 然后系统提示输入 user2 口令,输入正确的口令之后就可以切换到 user2。完成之后就可 以用 exit 命令返回到 user1。 su 命令的常见用法是变成根用户或超级用户。如果发出不带用户名的 su 命令 ,则系统 提示输入根口令,输入之后则可切换为根用户。 如果登录为根用户,则可以用 su 命令成为系统上任何用户而不需要口令。 3.2. pwd pwd 命令也是最常用最基本的命令之一,用于显示用户当前所在的目录。 3.3. cd cd 命令不仅显示当前状态,还可以改变当前状态,它的用法跟 dos 下的 cd 命令基本一致。 cd ..可进入上一层目录 cd -可进入上一个进入的目录 cd ~可进入用户的 home 目录 3.4. ls 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 36 页 共 175 页 双实科技 ls 命令跟 dos 下的 dir 命令一样,用于显示当前目录的内容。 如果想取得详细的信息,可用 ls -l 命令, 这样就可以显示目录内容的详细信息。 如果目录下的文件太多,用一屏显示不了,可以用 ls -l |more 分屏显示 。 3.5. cat cat 通常是用来在屏幕上滚动显示文件的内容。它的格式是: cat〈filename〉 3.6. find find 命令用于查找文件。这个命令可以按文件名、建立或修改日期、所有者(通常是建立 文件的用户)、文件长度或文件类型进行搜索。 find 命令的基本结构如下: $find 其中指定从哪个目录开始搜索。指定搜索条件。表示找到文件怎么处理。一般来说,要 用-print 动作,显示整个文件路径和名称。如果没有这个动作,则 find 命令进行所要搜索而不 显示结果。 例如,要搜索系统上所有名称为 ye 的文件,可用如下命令: $find / -name ye -print 3.7. tar tar 最初用于建立磁带备份系统,目前广泛用于建立文件发布档案。可用如下方法建立 tar 档案: $tar cvf 例如,如果要将当前目录中所有文件存档到 ye.tar 中,可用如下命令: $tar cvf ye.tar *.* 要浏览档案内容,将 c 选项变成 t。如果要浏览 ye.tar 档案中的内容,可用如下命令: $tar tvf ye.tar 要取出档案内的内容,将 c 选项变成 x。如果要将 ye.tar 档案中的内容取到当前目录中, 可用如下命令: $tar xvf ye.tar 3.8. gzip gzip 命令用于压缩文件。 例如,如果要将 ye.txt 文件压缩,可用如下命令: $gzip ye.txt 这样就可以压缩文件并在文件名后面加上 gz 扩展名,变成文件 ye.txt.gz。 解压缩文件可用 gzip -d 命令实现: $gzip -d ye.txt.gz 这样就可以解压缩文件并删除 gz 扩展名。除此之外还可以用 gunzip 命令来解压缩文件, 效果跟用 gzip -d 命令一样。 旧版的 tar 命令不压缩档案,可用 gzip 压缩。例如: $tar cvf ye.tar *.txt $gzip ye.tar 则可建立压缩档案 ye.tar.gz。 新版的 tar 可以直接访问和建立 gzip 压缩的 tar 档案,只要在 tar 命令中加上 z 选项就可 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 37 页 共 175 页 双实科技 以了。例如: $tar czvf ye.tar *.txt 生成压缩档案 ye.tar.gz, $tar tzvf ye.tar *.txt 显示压缩档案 ye.tar.gz 的内容,而 $tar xzvf ye.tar *.txt 取出压缩档案 ye.tar.gz 的内容。 3.9. mkdir 这个命令很简单,跟 dos 的 md 命令用法几乎一样,用于建立目录。 3.10.cp cp 命令用于复制文件或目录。 cp 命令可以一次复制多个文件,例如: $cp *.txt *.doc *.bak /home 将当前目录中扩展名为 txt、doc 和 bak 的文件全部复制到/home 目录中。 如果要复制整个目录及其所有子目录,可以用 cp -R 命令。 3.11.rm rm 命令用于删除文件或目录。 rm 命令会强制删除文件,如果想要在删除时提示确认,可用 rm -i 命令。 如果要删除目录,可用 rm -r 命令。rm -r 命令在删除目录时,每删除一个文件或目录都 会显示提示,如果目录太大,响应每个提示是不现实的。这时可以用 rm -rf 命令来强制删除 目录,这样即使用了-i 标志也当无效处理。 3.12.mv mv 命令用于移动文件和更名文件。例如: $mv ye.txt /home 将当前目录下的 ye.txt 文件移动到/home 目录下, $mv ye.txt ye1.txt 将 ye.txt 文件改名为 ye1.txt。 类似于 cp 命令,mv 命令也可以一次移动多个文件,在此不再赘叙。 3.13.mount 这个指令可以用来连接文件系统。例如,要访问光盘上的资料,假设光驱是第二个 IDE 口从盘,那么可以使用命令 mount /dev/hdd /cdrom 把光盘内容连接到/cdrom 下,在连接之前,/cdrom 目录必须存在。 连接后可以用 umount /cdrom 卸掉文件系统。 linux 支持多种可挂接的文件系统,例如,要挂接 IDE1 主盘的第二个分区上的 Windows 95 分区,使用命令 mount /dev/hda2 /dosc -t vfat 可以使用的描述符包括 msdos,ext2,vfat,umsdos,iso9660,ntfs 等 3.14.reboot 重启命令,不必多说。 3.15.halt 关机命令,不必多说。 4、 实验步骤 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 38 页 共 175 页 双实科技 这里应用 Linux 的各种命令对 Linux 内核代码进行漫游。 4.1 建立工作目录 Myjob 打开终端,输入下列命令: #mkdir /root/Myjob #cd /root/Myjob #pwd 4.2 输入下列命令,从光盘拷贝内核的压缩包到工作目录。 #cp /mnt/cdrom/SourceCode/Linux/kernel/s3c2440_kernel2.4.18_r2.0.tar.bz2 /root/Myjob 由于 Linux 版本的更新,文件名的后半部分经常会改动,文件名由于版本的改动而产生 的变化我们不会另行通知。请在输入带路径的命令前输入 ls 命令查看当前的文件名,可以在 输入完 s3c2440_kernel 后使用 TAB 键补全,而不直接输入。本书的余下部分都遵循这个原则。 4.3 解压缩内核 #tar –jxvf s3c2440_kernel2.4.18_r2.0.tar.bz2 #ls #cd s3c2440_kernel2.4.18_rel 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 39 页 共 175 页 双实科技 #ls 4.4 在内核中查找触摸屏驱动文件 s3c2440-ts.c #find –name “s3c2440-ts.c” 4.5 查看 s3c2440-ts.c 文件的内容 #cd /root/Myjob/s3c2440_kernel2.4.18_rel/driver/char #cat s3c2440-ts.c 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 40 页 共 175 页 双实科技 4.6 重新压缩内核 #cd /root/Myjob #tar –jcvf s3c2440_kernel2.4.18_Myjob.tar.bz2 s3c2440_kernel2.4.18_rel #ls 4.7 重命名 s3c2440_kernel2.4.18_Myjob.tar.bz2 #mv s3c2440_kernel2.4.18_Myjob.tar.bz2 s3c2440_kernel2.4.18_Myjob2.tar.bz2 #ls 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 41 页 共 175 页 双实科技 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 42 页 共 175 页 双实科技 2.2 Linux 下编辑器 VI 的操作 1、 实验目的 z 熟练运用 find,grep 命令定位需要修改的代码 z 熟练运用 vi 进行代码的编辑 2、 实验设备 z 硬件:PC 机 z 软件:Red Hat9 3、 实验原理 3.1. Linux 下的源代码编译工具 vi vi 编辑器是所有 Unix 及 Linux 系统下标准的编辑器,它的强大不逊色于任何最新的文本 编辑器,这里只是简单地介绍一下它的用法和一部分指令。由于对 Unix 及 Linux 系统的任何 版本,vi 编辑器是完全相同的,因此您可以在其他任何介绍 vi 的地方进一步了解它。vi 也是 Linux 中最基本的文本编辑器,学会它后,您将在 Linux 的世界里畅行无阻。 1. vi 的基本概念 基本上 vi 可以分为三种状态,分别是命令模式(command mode)、插入模式(Insert mode) 和底行模式(last line mode),各模式的功能区分如下: 1) 命令行模式 command mode) 控制屏幕光标的移动,字符、字或行的删除,移动复制某区段及进入 Insert mode 下, 或者到 last line mode。 2) 插入模式(Insert mode) 只有在 Insert mode 下,才可以做文字输入,按「ESC」键可回到命令行模式。 3) 底行模式(last line mode) 将文件保存或退出 vi,也可以设置编辑环境,如寻找字符串、列出行号……等。不过一 般我们在使用时把 vi 简化成两个模式,就是将底行模式(last line mode)也算入命令行模式 command mode)。 2. vi 的基本操作 1) 进入 vi 在系统提示符号输入 vi 及文件名称后,就进入 vi 全屏幕编辑画面: $ vi myfile 不过有一点要特别注意,就是您进入 vi 之后,是处于「命令行模式(command mode)」,您要切换到「插入模式(Insert mode)」才能够输入文字。 2) 切换至插入模式(Insert mode)编辑文件 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 43 页 共 175 页 双实科技 在「命令行模式(command mode)」下按一下字母「i」就可以进入「插入模式(Insert mode)」, 这时候你就可以开始输入文字了。 3) Insert 的切换 您目前处于「插入模式(Insert mode)」,您就只能一直输入文字,如果您发现输错了字! 想用光标键往回移动,将该字删除,就要先按一下「ESC」键转到「命令行模式(command mode) 」 再删除文字。 4) 退出 vi 及保存文件 在「命令行模式(command mode)」下,按一下「:」冒号键进入「Last line mode」,例 如: z : w filename (输入 「w filename」将文章以指定的文件名 filename 保存) z : wq (输入「wq」,存盘并退出 vi) z : q! (输入 q!, 不存盘强制退出 vi) 3. 命令行模式(command mode)功能键 1)插入模式 z 按「i」切换进入插入模式「insert mode」,按“i”进入插入模式后是从光标当前位置开 始输入文件; z 按「a」进入插入模式后,是从目前光标所在位置的下一个位置开始输入文字; z 按「o」进入插入模式后,是插入新的一行,从行首开始输入文字。 2)从插入模式切换为命令行模式 z 按「ESC」键。 3)移动光标 vi 可以直接用键盘上的光标来上下左右移动,但正规的 vi 是用小写英文字母「h」 、 「j」、 「k」 、「l」,分别控制光标左、下、上、右移一格。 z 按「ctrl」+「b」:屏幕往“后”移动一页。 z 按「ctrl」+「f」:屏幕往“前”移动一页。 z 按「ctrl」+「u」:屏幕往“后”移动半页。 z 按「ctrl」+「d」:屏幕往“前”移动半页。 z 按数字「0」 :移到文章的开头。 z 按「G」:移动到文章的最后。 z 按「$」:移动到光标所在行的“行尾”。 z 按「^」:移动到光标所在行的“行首” z 按「w」:光标跳到下个字的开头 z 按「e」:光标跳到下个字的字尾 z 按「b」:光标回到上个字的开头 z 按「#l」:光标移到该行的第#个位置,如:5l,56l。 4)删除文字 z 「x」:每按一次,删除光标所在位置的“后面”一个字符。 z 「#x」:例如,「6x」表示删除光标所在位置的“后面”6 个字符。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 44 页 共 175 页 双实科技 z 「X」:大写的 X,每按一次,删除光标所在位置的“前面”一个字符。 z 「#X」:例如,「20X」表示删除光标所在位置的“前面”20 个字符。 z 「dd」:删除光标所在行。 z 「#dd」:从光标所在行开始删除#行 z 5)复制 z 「yw」:将光标所在之处到字尾的字符复制到缓冲区中。 z 「#yw」:复制#个字到缓冲区 z 「yy」:复制光标所在行到缓冲区。 z 「#yy」:例如,「6yy」表示拷贝从光标所在的该行“往下数”6 行文字。 z 「p」:将缓冲区内的字符贴到光标所在位置。注意:所有与“y”有关的复制命令都必 须与“p”配合才能完成复制与粘贴功能。 6)替换 z 「r」:替换光标所在处的字符。 z 「R」:替换光标所到之处的字符,直到按下「ESC」键为止。 7)回复上一次操作 z 「u」:如果您误执行一个命令,可以马上按下「u」,回到上一个操作。按多次“u”可 以执行多次回复。 8)更改 z 「cw」:更改光标所在处的字到字尾处 z 「c#w」:例如,「c3w」表示更改 3 个字 9)跳至指定的行 z 「ctrl」+「g」列出光标所在行的行号。 z 「#G」:例如,「15G」,表示移动光标至文章的第 15 行行首。 4. Last line mode 下命令简介 在使用「last line mode」之前,请记住先按「ESC」键确定您已经处于「command mode」 下后,再按「:」冒号即可进入「last line mode」。 1) 列出行号 z 「set nu」:输入「set nu」后,会在文件中的每一行前面列出行号。 2) 跳到文件中的某一行 z 「#」 : 「#」号表示一个数字,在冒号后输入一个数字,再按回车键就会跳到该行了,如 输入数字 15,再回车,就会跳到文章的第 15 行。 3) 查找字符 z 「/关键字」:先按「/」键,再输入您想寻找的字符,如果第一次找的关键字不是您想要 的,可以一直按「n」会往后寻找到您要的关键字为止。 z 「?关键字」:先按「?」键,再输入您想寻找的字符,如果第一次找的关键字不是您想 要的,可以一直按「n」会往前寻找到您要的关键字为止。 4) 保存文件 z 「w」:在冒号输入字母「w」就可以将文件保存起来。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 45 页 共 175 页 双实科技 5) 离开 vi z 「q」:按「q」就是退出,如果无法离开 vi,可以在「q」后跟一个「!」强制离开 vi。 z 「qw」:一般建议离开时,搭配「w」一起使用,这样在退出的时候还可以保存文件。 3.2. Linux 下的模式搜索命令(grep、fgrep 和 egrep) 这组命令以指定模式搜索文件,并通知用户在什么文件中搜索到与指定的模式匹配的字 符串,并打印出所有包含该字符串的文本行,在该文本行的最前面是该行所在的文件名。grep 命令一次只能搜索一个指定的模式;egrep 命令检索扩展的正则表达式(包括表达式组和可选 项);fgrep 命令检索固定字符串,它不识别正则表达式,是快速搜索命令。 这组命令在搜索与定位文件中特定的主题方面非常有用。要搜索的模式可以被认为是一 些关键词,您可以用它们来搜索文件中包含的这些关键词。编写程序时,可以用它来寻找某 一个函数,或是相关的词组。grep 命令的搜索功能比 fgrep 强大,因为 grep 命令的搜索模式 可以是正则表达式,而 fgrep 却不能。 该组命令中的每一个命令都有一组选项,利用这些选项可以改变其输出方式。例如,可 以在搜索到的文本行上加入行号,或者只输出文本行的行号,或者输出所有与搜索模式不匹 配的文本行,或只简单地输出已搜索到指定模式的文件名,并且可以指定在查找模式时忽略 大小写。 这组命令在指定的输入文件中查找与模式匹配的行。如果没有指定文件,则从标准输入 中读取。正常情况下,每个匹配的行被显示到标准输出。如果要查找的文件是多个,则在每 一行输出之前加上文件名。 语法: grep [选项] [查找模式] [文件名 1,文件名 2,……] egrep [选项] [查找模式] [文件名 1,文件名 2,……] fgrep [选项] [查找模式] [文件名 1,文件名 2,……] 这组命令各选项的含义为: E 每个模式作为一个扩展的正则表达式对待。 F 每个模式作为一组固定字符串对待(以新行分隔),而不作为正则表 达式。 - b 在输出的每一行前显示包含匹配字符串的行在文件中的字节偏移量。 - c 只显示匹配行的数量。 - i 比较时不区分大小写。 - h 在查找多个文件时,指示 grep 不要将文件名加入到输出之前。 - l 显示首次匹配串所在的文件名并用换行符将其隔开。当在某文件中多 次出现匹配串时,不重复显示此文件名。 - n 在输出前加上匹配串所在行的行号(文件首行行号为 1) 。 - v 只显示不包含匹配串的行。 - x 只显示整行严格匹配的行。 - e expression 指定检索使用的模式。用于防止以“-”开头的模式被解释 为命令选项。 - f expfile 从 expfile 文件中获取要搜索的模式,一个模式占一行。 对该组命令的使用还需注意以下方面: 在命令后键入搜索的模式,再键入要搜索的文件。其中,文件名列表中也可以使用特殊 字符,如“*”等,用来生成文件名列表。如果想在搜索的模式中包含有空格的字符串,可以 用单引号把要搜索的模式括起来,用来表明搜索的模式是由包含空格的字符串组成。否则, - 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 46 页 共 175 页 双实科技 Shell 将把空格认为是命令行参数的定界符,而 grep 命令将把搜索模式中的单词解释为文件 名列表中的一部分。在下面的例子中,grep 命令在文件 example 中搜索模式“text file”。 $ grep ‘text file’ example 用户可以在命令行上用 Shell 特殊字符来生成将要搜索的文件名列表。在下面的例子中, 特殊字符“*”用来生成一个文件名列表,该列表包含当前目录下所有的文件。该命令将搜索 出当前目录下所有文件中与模式匹配的行。 $ grep data * 特殊字符在搜索一组指定的文件时非常有用。例如,如果想搜索所有的 C 程序源文件中 特定的模式,您可以用“*.c”来指定文件名列表。假设用户的 C 程序中包含一些不必要的转 向语句(goto 语句),想要找到这些语句,可以用如下的命令来搜索并显示所有包含 goto 语 句的代码行: $ grep goto *.c 用户可以在命令行上键入搜索模式,也可以使用-f 选项从指定文件中读取要搜索的模式。 在文件中,每个搜索模式占一行。如果经常要搜索一组常见字符串时,这个功能非常有用。 在下面的例子中,用户要在文件 exam 中搜索字符串“editor”和“create”,就把要搜索的模 式放置在文件 mypats 中,然后,grep 命令从文件 mypats 中读取要搜索的模式。 $ cat mypats editor create $ grep -f mypats exam 4、 实验步骤 4.1. 使用 vi 建立 Hello.c 文件 输入如下命令如图 1 所示 $cd /root/Myjob $vi hello.c 图1 4.2. 按 i 键进入插入模式,输入如下代码 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 47 页 共 175 页 双实科技 #include main() { printf(“Hello World!\n”); pritnf(“Hello SinoSys!\n”); } 如图 2 所示,然后按 ESC 键退出插入模式,进入底行模式输入 wq(回车)保存文件并 退出 vi。 图2 4.3. 使用 grep 在/root 中查找含有“Hello SinoSys”字符串的文件 在终端中输入如下命令,如图 3 所示 $ grep –r “Hello SinoSys” /root/Myjob 图3 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 48 页 共 175 页 双实科技 2.3 Minicom 实验 1、 实验目的 z 掌握 Linux 上的串口终端程序 minicom 的设置及其用法。 2、 实验设备 z 硬件:PC 机、SinoSys-M 系列实验箱 z 软件:Red Hat9 3、 实验原理 minicom 是个通信程序,有点象共享软件 TELIX,但其源码可以自由获得,并能够运行 于多数 Unix 系统。 它包括以下特性:自动重拨号的拨号目录, 对串行设备 UUCP 格式的 lock 文件的支持,独立的脚本语言解释器,文件捕获,多用户单独配置,等等。 4、 实验步骤 4.1. minicom 的执行 安装 linux 时基本上会安装 minicom。安装与否可用下面的指令来确认,如图 1 所示 #rpm -qa | grep minicom minicom-2.00.0-12 现在安装在 PC 上的 minicom 版本是 minicom-2.00.0-12。如果上面的指令找不到版本, 表示安装 RedHat Linux 没有选择完全安装。为了保证后面的实验能顺利完了,请完全安装 Linux。 图1 #minicom 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 49 页 共 175 页 双实科技 可看到如下 minicom 被执行的过程。如图 2 所示。 图2 在后面会进行设置和连接目标板,这里先退出 minicom。按 Ctrl+a,然后按 z,出来功能 框,按 x 然后选择 Yes 即退出。 4.2. minicom 设置 现在通过设置 minicom 了解连接目标板的方法。通过 minicom -s 选项进入 minicom 设置 画面,根据板子进行适当的设置。如图 2 所示。 #minicom –s 图 3 minicom 设置窗 上面的设置画面中选择 Serial port setup,如图 4 所示。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 50 页 共 175 页 双实科技 图 4 serial 设置窗 在这里进行如下 serial 设置。 1. 图 5 的设置窗弹出后按“a”键则光标会停在/dev/modem 后面。如果 Serial cable 连接在 com port 1 则将 Serial Device 设为/dev/ttySO,如果连接在 com port 2 则设为/dev/ttyS1,然后按回车键。 2. 按“e”键,弹出图 4 的窗则设定 speed,data bit,parity bit,stop bit。开发 板的设置为 speed-115200,data bit -8,panty bit-No,stop bit -1,应依此来 进行设置。按可同时设置的键“I” 即可。 图 5 Comm Parameters 窗 3. 按“f”键将 Hardware Flow Control 由 Yes 改为 No。Serial 设置完成后的结果如 图 6 所示。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 51 页 共 175 页 双实科技 图 6 minicom 设置 完成设置结束后用 Esc 键退出则返回到图 2。在这里要保存目前设定的值则选择 Save setup asdfl。保存后用 Esc 键退出。这样就会退出到 minicom,如图 6 所示。 4.3. 开启实验箱电源,引导 Linux 将 PC 机和目标板之间的串口电缆、实验箱的电源连接起来。打开实验箱的电源。(确保 实验箱的模式的选择开关在 NAND 的一边。我们在 NAND 上预烧了 Linux 操作系统。) 我们会在 minicom 中看到 Linux 从实验箱串口输出的启动信息。如图 7 所示。 图7 4.4. 在实验箱的 Linux 里再次熟习 Linux 的常用命令 在实验箱的嵌入式 Linux 里,再次熟习一个 Linux 的常用命令。如 cp、mv、mkdir 等。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 52 页 共 175 页 双实科技 2.4 Gcc 编译器 1、 实验目的 z 熟练运用 GCC 进行C语言编程 z 熟练运用 vi 进行代码的编辑 2、 实验设备 z 硬件:PC 机 z 软件:Red Hat9 3、 实验原理 3.1. gcc 简介 Linux 系统下的 gcc(GNU C Compiler)是 GNU 推出的功能强大、性能优越的多平台编 译器,是 GNU 的代表作品之一。gcc 是可以在多种硬体平台上编译出可执行程序的超级编译 器,其执行效率与一般的编译器相比平均效率要高 20%~30%。 gcc 编译器能将 C、C++语言源程序、汇编程序和目标程序编译、连接成可执行文件,如 果没有给出可执行文件的名字,gcc 将生成一个名为 a.out 的文件。在 Linux 系统中,可执行 文件没有统一的后缀,系统从文件的属性来区分可执行文件和不可执行文件。而 gcc 则通过 后缀来区别输入文件的类别,下面我们来介绍 gcc 所遵循的部分约定规则。 z .c 为后缀的文件,C 语言源代码文件; z .a 为后缀的文件,是由目标文件构成的档案库文件; z .C,.cc 或.cxx 为后缀的文件,是 C++源代码文件; z .h 为后缀的文件,是程序所包含的头文件; z .i 为后缀的文件,是已经预处理过的 C 源代码文件; z .ii 为后缀的文件,是已经预处理过的 C++源代码文件; z .m 为后缀的文件,是 Objective-C 源代码文件; z .o 为后缀的文件,是编译后的目标文件; z .s 为后缀的文件,是汇编语言源代码文件; z .S 为后缀的文件,是经过预编译的汇编语言源代码文件。 3.2. gcc 的执行过程 虽然我们称 gcc 是 C 语言的编译器,但使用 gcc 由 C 语言源代码文件生成可执行文件的 过程不仅仅是编译的过程,而是要经历四个相互关联的步骤∶预处理(也称预编译, Preprocessing)、编译(Compilation)、汇编(Assembly)和连接(Linking)。 命令 gcc 首先调用 cpp 进行预处理,在预处理过程中,对源代码文件中的文件包含 (include)、预编译语句(如宏定义 define 等)进行分析。接着调用 cc1 进行编译,这个阶段根据 输入文件生成以.o 为后缀的目标文件。汇编过程是针对汇编语言的步骤,调用 as 进行工作, 一般来讲,.S 为后缀的汇编语言源代码文件和汇编、.s 为后缀的汇编语言文件经过预编译和 汇编之后都生成以.o 为后缀的目标文件。当所有的目标文件都生成之后,gcc 就调用 ld 来完 成最后的关键性工作,这个阶段就是连接。在连接阶段,所有的目标文件被安排在可执行程 序中的恰当的位置,同时,该程序所调用到的库函数也从各自所在的档案库中连到合适的地 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 53 页 共 175 页 双实科技 方。 3.3. gcc 的基本用法和选项 在使用 gcc 编译器的时候,我们必须给出一系列必要的调用参数和文件名称。gcc 编译器 的调用参数大约有 100 多个,其中多数参数我们可能根本就用不到,这里只介绍其中最基本、 最常用的参数。 gcc 最基本的用法是∶gcc [options] [filenames] 其中 options 就是编译器所需要的参数,filenames 给出相关的文件名称。 -x language filename 设定文件所使用的语言,使后缀名无效,对以后的多个有效。也就是根据约定 C 语言的后缀 名称是.c 的,而 C++的后缀名是.C 或者.cpp,如果你决定你的 C 代码文件的后缀名是.pig, 那你就要用这个参数,这个参数对他后面的文件名都起作用,除非到了下一个参数的使用。 可以使用的参数有下面的这些: `c', `objective-c', `c-header', `c++', `cpp-output', `assembler', and `assembler-with-cpp'. 例子用法: gcc -x c hello.pig -x none filename 关掉上一个选项,也就是让 gcc 根据文件名后缀,自动识别文件类型 例子用法: gcc -x c hello.pig -x none hello2.c -c 只激活预处理,编译,和汇编,也就是他只把程序做成 obj 文件 例子用法: gcc -c hello.c 将生成.o 的 obj 文件 -S 只激活预处理和编译,就是指把文件编译成为汇编代码。 例子用法 gcc -S hello.c 他将生成.s 的汇编代码,你可以用文本编辑器查看 -E 只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面。 例子用法: gcc -E hello.c > pianoapan.txt gcc -E hello.c | more 一个 hello word 也要与处理成 800 行的代码 -o 制定目标名称,缺省的时候,gcc 编译出来的文件是 a.out。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 54 页 共 175 页 双实科技 例子用法 gcc -o hello.exe hello.c gcc -o hello.asm -S hello.c -pipe 使用管道代替编译中临时文件,在使用非 gnu 汇编工具的时候,可能有些问题 gcc -pipe -o hello.exe hello.c -ansi 关闭 gnu c 中与 ansi c 不兼容的特性,激活 ansi c 的专有特性(包括禁止一些 asm inline typeof 关键字,以及 UNIX,vax 等预处理宏。 -fno-asm 此选项实现 ansi 选项的功能的一部分,它禁止将 asm,inline 和 typeof 用作关键字。 -fno-strict-prototype 只对 g++起作用,使用这个选项,g++将对不带参数的函数,都认为是没有显示的对参数的 个数和类型说明,而不是没有参数。而 gcc 无论是否使用这个参数,都将对没有带参数的 函数,认为成没有显示说明的类型。 -fthis-is-varialble 就是向传统 c++看齐,可以使用 this 当一般变量使用。 -fcond-mismatch 允许条件表达式的第二和第三参数类型不匹配,表达式的值将为 void 类型 -funsigned-char -fno-signed-char -fsigned-char -fno-unsigned-char 这四个参数是对 char 类型进行设置,决定将 char 类型设置成 unsigned char(前两个参数) 或者 signed char(后两个参数) -include file 包含某个代码,简单来说,就是便以某个文件,需要另一个文件的时候,可以用它设定,功能 就相当于在代码中使用#include 例子用法: gcc hello.c -include /root/pianopan.h -imacros file 将 file 文件的宏,扩展到 gcc/g++的输入文件,宏定义本身并不出现在输入文件中。 -Dmacro 相当于 C 语言中的#define macro 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 55 页 共 175 页 双实科技 -Dmacro=defn 相当于 C 语言中的#define macro=defn -Umacro 相当于 C 语言中的#undef macro -undef 取消对任何非标准宏的定义 -Idir 在你是用#include"file"的时候,gcc/g++会先在当前目录查找你所制定的头文件,如果没有 找到,回到缺省的头文件目录找,如果使用-I 制定了目录,会先在你所制定的目录查找,然 后再按常规的顺序去找。对于#include,gcc/g++会到-I 制定的目录查找,查找不到,然后将 到系统的缺省的头文件目录查找。 -I就是取消前一个参数的功能,所以一般在-Idir 之后使用。 -idirafter dir 在-I 的目录里面查找失败,将到这个目录里面查找。 -iprefix prefix -iwithprefix dir 一般一起使用,当-I 的目录查找失败,会到 prefix+dir 下查找。 -nostdinc 使编译器不再系统缺省的头文件目录里面找头文件,一般和-I 联合使用,明确限定头文件 的位置。 -nostdin C++ 规定不在 g++指定的标准路径中搜索,但仍在其他路径中搜索,.此选项在创建 libg++库使 用。 -C 在预处理的时候,不删除注释信息,一般和-E 使用,有时候分析程序。 -M 生成文件关联的信息。包含目标文件所依赖的所有源代码。 你可以用 gcc -M hello.c 来测试一下。 -MM 和上面的-M 一样,但是它将忽略由#include 造成的依赖关系。 -MD 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 56 页 共 175 页 双实科技 和-M 相同,但是输出将导入到.d 的文件里面 -MMD 和-MM 相同,但是输出将导入到.d 的文件里面 -Wa,option 此选项传递 option 给汇编程序;如果 option 中间有逗号,就将 option 分成多个选项,然后传 递给会汇编程序 -Wl.option 此选项传递 option 给连接程序;如果 option 中间有逗号,就将 option 分成多个选项,然后传 递给会连接程序. -llibrary 制定编译的时候使用的库 例子用法 gcc -lcurses hello.c 使用 ncurses 库编译程序 -Ldir 制定编译的时候,搜索库的路径。比如你自己的库,可以用它制定目录,不然编译器将 只在标准库的目录找。这个 dir 就是目录的名称。 -O0 -O1 -O2 -O3 编译器的优化选项的 4 个级别,-O0 表示没有优化,-O1 为缺省值,-O3 优化级别最高 -g 只是编译器,在编译的时候,产生调试信息。 -gstabs 此选项以 stabs 格式生成调试信息,但是不包括 gdb 调试信息。 -gstabs+ 此选项以 stabs 格式生成调试信息,并且包含仅供 gdb 使用的额外调试信息。 -ggdb 此选项将尽可能的生成 gdb 的可以使用的调试信息. -static 此选项将禁止使用动态库,所以,编译出来的东西,一般都很大,也不需要什么动态连 接库,就可以运行。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 57 页 共 175 页 双实科技 -share 此选项将尽量使用动态库,所以生成文件比较小,但是需要系统有动态库。 -traditional 试图让编译器支持传统的 C 语言特性 3.4. gcc 的错误类型及对策 gcc 编译器如果发现源程序中有错误,就无法继续进行,也无法生成最终的可执行文件。 为了便于修改,gcc 给出错误资讯,我们必须对这些错误资讯逐个进行分析、处理,并修改相 应的语言,才能保证源代码的正确编译连接。gcc 给出的错误资讯一般可以分为四大类,下面 我们分别讨论其产生的原因和对策。 第一类∶C 语法错误 错误资讯∶文件 source.c 中第 n 行有语法错误(syntex errror)。这种类型的错误,一般都是 C 语言的语法错误,应该仔细检查源代码文件中第 n 行及该行之前的程序,有时也需要对该 文件所包含的头文件进行检查。 第二类∶头文件错误 错误资讯∶找不到头文件 head.h(Can not find include file head.h)。这类错误是源代码文件 中的包含头文件有问题,可能的原因有头文件名错误、指定的头文件所在目录名错误等,也 可能是错误地使用了双引号和尖括号。 第三类∶档案库错误 错误资讯∶连接程序找不到所需的函数库,例如∶ ld: -lm: No such file or directory 这类错误是与目标文件相连接的函数库有错误,可能的原因是函数库名错误、指定的函 数库所在目录名称错误等,检查的方法是使用 find 命令在可能的目录中寻找相应的函数库名, 确定档案库及目录的名称并修改程序中及编译选项中的名称。 第四类∶未定义符号 错误资讯∶有未定义的符号(Undefined symbol)。这类错误是在连接过程中出现的,可能 有两种原因∶一是使用者自己定义的函数或者全局变量所在源代码文件,没有被编译、连接, 或者干脆还没有定义,这需要使用者根据实际情况修改源程序,给出全局变量或者函数的定 义体;二是未定义的符号是一个标准的库函数,在源程序中使用了该库函数,而连接过程中 还没有给定相应的函数库的名称,或者是该档案库的目录名称有问题,这时需要使用档案库 维护命令 ar 检查我们需要的库函数到底位于哪一个函数库中,确定之后,修改 gcc 连接选项 中的-l 和-L 项。 排除编译、连接过程中的错误,应该说这只是程序设计中最简单、最基本的一个步骤, 可以说只是开了个头。这个过程中的错误,只是我们在使用 C 语言描述一个算法中所产生的 错误,是比较容易排除的。我们写一个程序,到编译、连接通过为止,应该说刚刚开始,程 序在运行过程中所出现的问题,是算法设计有问题,还需要更加深入地测试、调试和修改。 一个程序,稍为复杂的程序,往往要经过多次的编译、连接和测试、修改。下面我们学习的 程序维护、调试工具和版本维护就是在程序调试、测试过程中使用的,用来解决调测阶段所 出现的问题。 4、 实验步骤 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 58 页 共 175 页 双实科技 4.1. 打开终端,输入下面命令新建 echo.c 文件 $cd /root/Myjob $vi echo.c 4.2. 输入下面程序实现字符的回显 #include char buf[256]; main() { printf(“Please enter a string..\n”); scanf(“%s”,buf); printf(“The string you enter is:%s\n”,buf); } 如图 1 所示 图1 4.3. 编译 echo.c 文件 输入下面命令,编译 echo.c 文件,用 file 命令测试生成的文件的文件类型,然后用 ldd 命令查看我们的这个程序使用了什么动态连接库。如图 2 所示。 $gcc –o echo echo.c $file echo $ldd echo 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 59 页 共 175 页 双实科技 图2 从上面的结果可以看出来,我们的这个程序使用了 libc.so.6 这个动态库文件,这是由于 在我们的程序里使用了“include ”。它指示连接程序,我们的程序使用的C语言标准 库里面的例程。我们再回头看一下代码,其实代码里面的 printf 和 scanf 函数都是标准C库里 面的例程。 4.4. 测试 echo 程序 运行下面命令来测试刚才生成的 echo 程序是否能完成我们想要的功能,如图 3 所示 $./echo 图3 这里要注意的是在 Linux 下,运行当前目录的程序要在程序前面加上”./”表示当前目录, 不然的话,系统将会按照 PATH 环境变量指定的路径去查找这个程序。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 60 页 共 175 页 双实科技 2.5 GDB 调试器 1、实验目的 z 熟练运用 GDB 进行C语言调试 z 熟练运用 vi 进行代码的编辑 2、实验设备 z 硬件:PC 机 z 软件:Red Hat9 3、实验原理 3.1. 引言 在了解 GDB 可以做什么,怎么做之前,让我们先来看看为什么要用 GDB,或者说对调 试工具有什么期望。 一般我们使用 GDB(或其他调试工具)是为了发现程序 bug,更经常地是在已知程序有错的 情况下定位 bug。既然这样,我们就需要跟踪程序的执行情况,查看程序执行是否正常,当然 这就需要有个让我们与执行程序交互的环境,调试工具提供一个能让程序在你的掌控下执行, 并让你能够查看一些执行过程中的“内幕信息”的环境。 为了查看程序运行过程中的状态,我们就希望程序能在适当的位置或者在一定的条件下 能够暂停运行;为此,调试工具提供了断点、查看变量/表达式、显示程序栈等功能。看了某 个点的“内幕”后,我们还期望更多,所以要能控制程序运行才行,这就要求断点、继续运 行、单步(多步)运行、进入函数运行等功能,在某些情况下,还需要通过修改当前的执行 环境(变量等)来达到期望的执行顺序。也就是说,光看着是不够的,还需要能改才行。 理解了这些问题后,我们就明白 GDB 的各个功能的用意了,自然也就明白该如何使用调试工 具了。当然,要让 GDB 有效的发挥作用,还是需要一定的经验与技巧,而这主要靠实践,学 习资料充其量只能帮你一把。 总而言之,我们首先要明白使用调试工具的目的和用意,才能理解它的各项功能,才能 借助它快速有效的发现问题;否则,即使工具再强大,你也不知道该如何使用才好。 另外要多结合使用代码监视、运行日志、测试工具等方法来发现潜在的问题,提高程序的质 量。 3.2. GDB 能做什么 GDB 可以用来调试 C、C++、Modula-2 的程序。一般来说,GDB 能做的事大致可以分为 四类: 1 2 3 4 启动程序,按指定的方式执行程序。 在指定条件下使程序暂停. 当程序被停住时,可以检查此时程序中的变化。 改变程序中的变量或执行顺序来试验。 3.3. GDB 使用概述 首先要了解的是 gdb 的 help 命令,因为你可能记不住各个命令的语法和用途,但只要能 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 61 页 共 175 页 双实科技 正确使用 help 命令,你就不需要任何其它的 gdb 资料。 启动 gdb 后,输入 help [eric@linux eric]$ gdb GNU gdb Red Hat Linux (5.3.90-0.20030710.40rh) Copyright 2003 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i386-redhat-linux-gnu". (gdb) help List of classes of commands: aliases -- Aliases of other commands breakpoints -- Making program stop at certain points data -- Examining data files -- Specifying and examining files internals -- Maintenance commands obscure -- Obscure features running -- Running the program stack -- Examining the stack status -- Status inquiries support -- Support facilities tracepoints -- Tracing of program execution without stopping the program user-defined -- User-defined commands Type "help" followed by a class name for a list of commands in that class. Type "help" followed by command name for full documentation. Command name abbreviations are allowed if unambiguous. (gdb) 如上文显示,gdb 的命令很多,所以把它分成许多个种类。help 命令只是例出 gdb 的命令 种类,如果要看某类中的命令,可以使用 help 命令,如:help breakpoints,查看设置 断点的所有命令。当然也可以直接 help 来查看某个命令的具体信息。 gdb 技巧:在记不清整个命令时,可以只打命令的前一个或几个字符,然后敲击两次 TAB 键来列出所有以这几个字符开头的命令;另外, 大多命令都有缩写,如 b 同 break, c 同 continue, n 同 next,p 同 print 等。另外,一个命令在输入能唯一标示命令的前缀后,按一下 TAB 键就 能补齐命令的全称,比如输入 ba 后按一下 TAB 键,就自动补齐为 backtrace,输入 pr 后按一 下 TAB 键就补齐为 print。 3.4. 为调试编译代码 为了使 gdb 正常工作, 你必须使你的程序在编译时包含调试信息. 调试信息包含你程序 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 62 页 共 175 页 双实科技 里的每个变量的类型和在可执行文件里的地址映射以及源代码的行号. gdb 利用这些信息使 源代码和机器码相关联,在编译时用 -g 选项打开调试选项.。 3.5. 在 GDB 中运行程序 当以 gdb 方式启动 gdb 后,可以使用 r 或是 run 命令运行程序。在程序运行之 前,你可能需要设置下面的四个方面。 ¾ 程序运行参数。 set args 可指定运行时参数。(如:set args 10 20 30 40 50) show args 命令可以查看设置好的运行参数。 ¾ 运行环境。 path 可设定程序的运行路径。 show paths 查看程序的运行路径。 set environment varname [=value] 设置环境变量。如:set env USER=hchen show environment [varname] 查看环境变量。 ¾ 工作目录。 cd 相当于 shell 的 cd 命令。 pwd 显示当前的所在目录。 ¾ 程序的输入输出。 info terminal 显示你程序用到的终端的模式。 使用重定向控制程序输出。如:run > outfile tty 命令可以指定输入输出的终端设备。如:tty /dev/ttyb 3.6. 调试已运行的程序 可以有两种方法调试已运行程序: 1 2 用 ps 查看正在运行的程序的进程 ID,然后用 gdb PID 格式挂接正在运行 的程序。 先用 gdb 关联上程序,并进行 gdb,在 gdb 中用 attach 命令来挂接程序正 在运行的进程。detach 可用来取消挂接的进程。 3.7. 暂停/恢复程序运行 你可以使用 info program 来查看程序的当前的执行状态。 在 gdb 中,我们可以有以下几种暂停方式:断点(BreakPoint)、观察点(WatchPoint)、 捕捉点(CatchPoint)、信号(Signals) 、线程停止(Thread Stops)。如果要恢复程序运行,可 以使用 c 或是 continue 命令。 1. 查看变量/表达式的值 可以使用 print expr(或 p expr)来查看程序变量/表达式的值 2. 显示程序栈 可以使用 backtrace(或 bt)来显示程序栈 3. 单步跟踪 next [n] 执行下一条(或 n 条)语句,不进入子程序 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 63 页 共 175 页 双实科技 step [n] 执行下一条(或 n 条)语句,进入子程序,可用 finish 从子程序返回 3.8. GDB 常用命令 backtrace 显示程序中的当前位置和表示如何到达当前位置的栈跟踪(同义词:where) breakpoint 在程序中设置一个断点 cd 改变当前工作目录 clear 删除刚才停止处的断点 commands 命令中断点时,列出将要执行的命令 continue 从断点开始继续执行 delete 删除一个断点或监测点;也可与其他命令一起使用 display 程序停止时显示变量和表达式 down 下移栈帧,使得另一个函数成为当前函数 frame 选择下一条 continue 命令的帧 info 显示与该程序有关的各种信息 jump 在源程序中的另一点开始运行 kill 异常终止在 gdb 控制下运行的程序 list 列出相应于正在执行的程序的原文件内容 next 执行下一个源程序行,从而执行其整体中的一个函数 print 显示变量或表达式的值 pwd 显示当前工作目录 pype 显示一个数据结构(如一个结构或 C++类)的内容 quit 退出 gdb reverse-search 在源文件中反向搜索正规表达式 run 执行该程序 search 在源文件中搜索正规表达式 set variable 给变量赋值 signal 将一个信号发送到正在运行的进程 step 执行下一个源程序行,必要时进入下一个函数 undisplay display 命令的反命令,不要显示表达式 until 结束当前循环 up 上移栈帧,使另一函数成为当前函数 watch 在程序中设置一个监测点(即数据断点) whatis 显示变量或函数类型 命令的具体使用方法请用上面介绍的 help 查询。 4.实验步骤 4.1. 首先,使用 vi 生成 test.c 文件,文件内容如下: #include int sum(int m); int main() { 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 64 页 共 175 页 双实科技 int i , n=0; sum(50); for(i=1; i<=50; i++) { n +=1; } printf(“The sum of 1-50 is %d \n”, n ); } int sum(int m) { int i ,n =0; for (i=1; i int sum(int m); int main() { int i , n=0; sum(50); for(i=1; i<=50; i++) { n +=1; } printf(“The sum of 1-50 is %d \n”, n ); } 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 72 页 共 175 页 双实科技 int sum(int m) { int i ,n =0; for (i=1; i filename 可以是当前操作系统 Shell 的文件模式(可以包含路径和通配符) 在 include 前面可以有一些空字符,但是绝不能是[Tab]键开始。include 可以用一个或多 个空格隔开。举个例子,你有这样几个 Makefile:a.mk、b.mk、c.mk,还有一个文件叫 foo.make, 以及一个变量$(bar),其包含了 e.mk 和 f.mk,那么,下面的语句: include foo.make *.mk $(bar) 等价于: include foo.make a.mk b.mk c.mk e.mk f.mk make 命令开始时,会把找寻 include 所指出的其它 Makefile,并把其内容安置在当前的 位置。就好像 C/C++的#i nclude 指令一样。如果文件都没有指定绝对路径或是相对路径的话, make 会在当前目录下首先寻找,如果当前目录下没有找到,那么,make 还会在下面的几个 目录下找: 1) 如果 make 执行时,有“-I”或“--include-dir”参数,那么 make 就会在这个参数所 指定的目录下去寻找。 2) 如果目录/include(一般是:/usr/local/bin 或/usr/include)存在的话,make 也会去找。 如果有文件没有找到的话,make 会生成一条警告信息,但不会马上出现致命错误。 它会继续载入其它的文件,一旦完成 makefile 的读取,make 会再重试这些没有找到, 或是不能读取的文件,如果还是不行,make 才会出现一条致命信息。如果你想让 make 不理那些无法读取的文件,而继续执行,你可以在 include 前加一个减号“-”。 如: -include 其表示,无论 include 过程中出现什么错误,都不要报错继续执行。和其它版本 make 兼 容的相关命令是 sinclude,其作用和这一个是一样的。 3.5. 环境变量 MAKEFILES 如果你的当前环境中定义了环境变量 MAKEFILES,那么,make 会把这个变量中的值做 一个类似于 include 的动作。这个变量中的值是其它的 Makefile,用空格分隔。只是,它和 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 75 页 共 175 页 双实科技 include 不同的是,从这个环境变中引入的 Makefile 的“目标”不会起作用,如果环境变量中 定义的文件发现错误,make 也会不理。 但是在这里我还是建议不要使用这个环境变量,因为只要这个变量一被定义,那么当你 使用 make 时,所有的 Makefile 都会受到它的影响,这绝不是你想看到的。在这里提这个事, 只是为了告诉大家,也许有时候你的 Makefile 出现了怪事,那么你可以看看当前环境中有没 有定义这个变量。 3.6. make 的工作方式 1) GNU 的 make 工作时的执行步骤入下: (想来其它的 make 也是类似) 2) 读入所有的 Makefile。 3) 读入被 include 的其它 Makefile。 4) 初始化文件中的变量。 5) 推导隐晦规则,并分析所有规则。 6) 为所有的目标文件创建依赖关系链。 7) 根据依赖关系,决定哪些目标要重新生成。 8) 执行生成命令。 1- 5 步为第一个阶段,6-7 为第二个阶段。第一个阶段中,如果定义的变量被使用了,那 么,make 会把其展开在使用的位置。但 make 并不会完全马上展开, make 使用的是拖延战 术,如果变量出现在依赖关系的规则中,那么仅当这条依赖被决定要使用了,变量才会在其 内部展开。 当然,这个工作方式你不一定要清楚,但是知道这个方式你也会对 make 更为熟悉。有了 这个基础,后续部分也就容易看懂了。 3.7. 书写规则 规则包含两个部分,一个是依赖关系,一个是生成目标的方法。 在 Makefile 中,规则的顺序是很重要的,因为,Makefile 中只应该有一个最终目标,其 它的目标都是被这个目标所连带出来的,所以一定要让 make 知道你的最终目标是什么。一般 来说,定义在 Makefile 中的目标可能会有很多,但是第一条规则中的目标将被确立为最终的 目标。如果第一条规则中的目标有很多个,那么,第一个目标会成为最终的目标。make 所完 成的也就是这个目标。 好了,还是让我们来看一看如何书写规则。 1) 规则举例 foo.o : foo.c defs.h cc -c -g foo.c # foo 模块 看到这个例子,各位应该不是很陌生了,前面也已说过,foo.o 是我们的目标,foo.c 和 defs.h 是目标所依赖的源文件,而只有一个命令“cc -c -g foo.c”(以 Tab 键开头)。这个规则 告诉我们两件事: 文件的依赖关系,foo.o 依赖于 foo.c 和 defs.h 的文件,如果 foo.c 和 defs.h 的文件日期要 比 foo.o 文件日期要新,或是 foo.o 不存在,那么依赖关系发生。 如果生成(或更新)foo.o 文件。也就是那个 cc 命令,其说明了,如何生成 foo.o 这个文件。 (当然 foo.c 文件 include 了 defs.h 文件) 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 76 页 共 175 页 双实科技 2) 规则的语法 targets : prerequisites command ... 或是这样: targets : prerequisites ; command command ... targets 是文件名,以空格分开,可以使用通配符。一般来说,我们的目标基本上是一个 文件,但也有可能是多个文件。 command 是命令行,如果其不与“target:prerequisites”在一行,那么,必须以[Tab 键]开 头,如果和 prerequisites 在一行,那么可以用分号做为分隔。 (见上) prerequisites 也就是目标所依赖的文件(或依赖目标)。如果其中的某个文件要比目标文 件要新,那么,目标就被认为是“过时的”,被认为是需要重生成的。这个在前面已经讲过了。 如果命令太长,你可以使用反斜杠(‘\’)作为换行符。make 对一行上有多少个字符没有 限制。规则告诉 make 两件事,文件的依赖关系和如何生成目标文件。 一般来说,make 会以 UNIX 的标准 Shell,也就是/bin/sh 来执行命令。 3) 在规则中使用通配符 如果我们想定义一系列比较类似的文件,我们很自然地就想起使用通配符。make 支持三 个通配符:“*” ,“?”和“[...]”。这是和 Unix 的 B-Shell 是相同的。 波浪号(“~”)字符在文件名中也有比较特殊的用途。如果是“~/test”,这就表示当前用 户的$HOME 目录下的 test 目录。而 “~hchen/test”则表示用户 hchen 的宿主目录下的 test 目 录。(这些都是 Unix 下的小知识了,make 也支持)而在 Windows 或是 MS-DOS 下,用户没 有宿主目录,那么波浪号所指的目录则根据环境变量“HOME”而定。 通配符代替了你一系列的文件,如“*.c”表示所以后缀为 c 的文件。一个需要我们注意 的是,如果我们的文件名中有通配符,如:“*”,那么可以用转义字符“\”,如“\*”来表示 真实的“*”字符,而不是任意长度的字符串。 还是先来看几个例子: clean: rm -f *.o 这是操作系统 Shell 所支持的通配符。这是在命令中的通配符。 print: *.c lpr -p $? touch print 面这个例子说明了通配符也可以用在我们的规则中,目标 print 依赖于所有的[.c]文件。其 中的“$?”是一个自动化变量,会在后面讲述。 objects = *.o 上面这个例子,表示了,通配符同样可以用在变量中。并不是说[*.o]会展开,objects 的 值就是“*.o” 。Makefile 中的变量其实就是 C/C++中的宏。如果你要让通配符在变量中展开, 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 77 页 共 175 页 双实科技 也就是让 objects 的值是所有[.o]的文件名的集合,那么,你可以这样: objects := $(wildcard *.o) 这种用法由关键字“wildcard”指出,关于 Makefile 的关键字,我们将在后面讨论。 4) 文件搜寻 在一些大的工程中,有大量的源文件,我们通常的做法是把这许多的源文件分类,并存 放在不同的目录中。所以,当 make 需要去找寻文件的依赖关系时,你可以在文件前加上路径, 但最好的方法是把一个路径告诉 make,让 make 在自动去找。 Makefile 文件中的特殊变量“VPATH”就是完成这个功能的,如果没有指明这个变量, make 只会在当前的目录中去找寻依赖文件和目标文件。如果定义了这个变量,那么,make 就会在当前目录找不到的情况下,到所指定的目录中去找寻文件了。 VPATH = src:../headers 上面的定义指定两个目录, “src”和“../headers” ,make 会按照这个顺序进行搜索。目录 由“冒号”分隔。(当然,当前目录永远是最高优先搜索的地方) 另一个设置文件搜索路径的方法是使用 make 的“vpath”关键字(注意,它是全小写的), 这不是变量,这是一个 make 的关键字,这和上面提到的那个 VPATH 变量很类似,但是它更 为灵活。它可以指定不同的文件在不同的搜索目录中。这是一个很灵活的功能。它的使用方 法有三种: vpath 为符合模式的文件指定搜索目录。 vpath 清除符合模式的文件的搜索目录。 vpath 清除所有已被设置好了的文件搜索目录。 vapth 使用方法中的需要包含“%”字符。 “%”的意思是匹配零或若干字符,例如, “%.h” 表示所有以“.h”结尾的文件。指定了要搜索的文件集,而则指定了的文件集的搜索的目录。 例如: vpath %.h ../headers 该语句表示,要求 make 在“../headers”目录下搜索所有以“.h”结尾的文件。 (如果某文件在 当前目录没有找到的话) 我们可以连续地使用 vpath 语句,以指定不同搜索策略。如果连续的 vpath 语句中出现了 相同的,或是被重复了的,那么,make 会按照 vpath 语句的先后顺序来执行搜索。 如: vpath %.c foo vpath % blish vpath %.c bar 其表示“.c”结尾的文件,先在“foo”目录,然后是“blish” ,最后是“bar”目录。 vpath %.c foo:bar vpath % blish 而上面的语句则表示“.c”结尾的文件,先在“foo”目录,然后是“bar”目录,最后才 是“blish”目录。 5) 伪目标 开始的一个例子中,我们提到过一个“clean”的目标,这是一个“伪目标”, 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 78 页 共 175 页 双实科技 clean: rm *.o temp 正像我们前面例子中的“clean”一样,即然我们生成了许多编译文件,我们也应该提供 一个清除它们的“目标”以备完整地重编译而用。 (以“make clean”来使用该目标) 因为,我们并不生成“clean”这个文件。 “伪目标”并不是一个文件,只是一个标签,由于“伪 目标”不是文件,所以 make 无法生成它的依赖关系和决定它是否要执行。我们只有通过显示 地指明这个“目标”才能让其生效。当然, “伪目标”的取名不能和文件名重名,不然其就失 去了“伪目标”的意义了。 当然,为了避免和文件重名的这种情况,我们可以使用一个特殊的标记“.PHONY”来显 示地指明一个目标是“伪目标”,向 make 说明,不管是否有这个文件,这个目标就是“伪目 标”。 .PHONY : clean 只要有这个声明,不管是否有“clean”文件,要运行“clean”这个目标,只需“make clean” 就可以了。于是整个过程可以这样写: .PHONY: clean clean: rm *.o temp 伪目标一般没有依赖的文件。但是,我们也可以为伪目标指定所依赖的文件。伪目标同 样可以作为“默认目标” ,只要将其放在第一个。一个示例就是,如果你的 Makefile 需要一 口气生成若干个可执行文件,但你只想简单地敲一个 make 完事,并且,所有的目标文件都写 在一个 Makefile 中,那么你可以使用“伪目标”这个特性: all : prog1 prog2 prog3 .PHONY : all prog1 : prog1.o utils.o cc -o prog1 prog1.o utils.o prog2 : prog2.o cc -o prog2 prog2.o prog3 : prog3.o sort.o utils.o cc -o prog3 prog3.o sort.o utils.o 我们知道,Makefile 中的第一个目标会被作为其默认目标。我们声明了一个“all”的伪 目标,其依赖于其它三个目标。由于伪目标的特性是,总是被执行的,所以其依赖的那三个 目标就总是不如“all”这个目标新。所以,其它三个目标的规则总是会被决议。也就达到了 我们一口气生成多个目标的目的。 “.PHONY : all”声明了“all”这个目标为“伪目标”。 顺便提一句,从上面的例子我们可以看出,目标也可以成为依赖。所以,伪目标同样也可成 为依赖。看下面的例子: .PHONY: cleanall cleanobj cleandiff cleanall : cleanobj cleandiff rm program cleanobj : 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 79 页 共 175 页 双实科技 rm *.o cleandiff : rm *.diff “make clean”将清除所有要被清除的文件。 “cleanobj”和“cleandiff”这两个伪目标有 点像“子程序”的意思。我们可以输入“make cleanall”和“make cleanobj”和“make cleandiff” 命令来达到清除不同种类文件的目的。 4、 实验步骤 4.1. 用 vi 在同一目录下编辑两个简单的 Hello 程序,如下所示: 打开终端,输入如下命令进立 hello.h 和 hello.c 两个文件。 #mkdir /root/Myjob/MakefileTest #cd /root/Myjob/MakefileTest #vi hello.c 输入以下程序然后保存退出 vi #include “hello.h” int main() { printf(“Hello everyone!\n”); } #vi hello.h 输入以下程序然后保存退出 vi 如图 1 所示 #include 终端中用 GCC 尝试编译 输入如下命令: #gcc hello.c –o hello #./hello 如图 1 所示 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 80 页 共 175 页 双实科技 图1 4.2. 用 vi 编缉 Makefile 输入如下命令创建 Makefile,且并不使用变量替换,用一个目标体实现(即直接将 hello.c 和 hello.h 编译成 hello 目标体)。然后用 make 验证所编写的 Makefile 是否正确。 #vi Makefile 然后在 vi 中输入如下内容(“gcc”前要加“TAB”键) hello:hello.c hello.h gcc hello.c –o hello 用 make 编译 退出 vi 并保存 Makefile 在终端中输下面命令检证 Makefile #make #./hello 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 81 页 共 175 页 双实科技 图2 编辑 Makefile 输入下面命令,并将上面的 Makefile 使用变量替换实现。 #vi Makefile 修改 Makefile 为如下的内容 OBJS :=hello.o CC :=gcc hello:$(OBJS) $(CC) $^ -o $@ 用 make 编译 退出 vi 并保存 Makefile 在终端中输下面命令检证 Makefile #make #./hello 图3 创建自定义文件名的 Makefile 输入如下命令创建 MakeMyjob,不用变量替换,但用两个目标体实现(也就首先将 hello.c 和 hello.h 编译成 hello.o,再将 hello.o 编译为 hello) 。 #vi Makefile 然后在 vi 中输入如下内容 OBJS1 := hello.o OBJS2 :=hello.c hello.h CC :=gcc hello:$(OBJS1) $(CC) $^ -o $@ 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 82 页 共 175 页 双实科技 $(OBJS1):$(OBJS2) $(CC) –c $< -o $@ 用 make 编译 退出 vi 并保存 Makefile,在终端中输下面命令检证 Makefile #make –f MakeMyjob #./hello 图4 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 83 页 共 175 页 双实科技 2.8 通过 JTAG 口下载映像到开发板 1、 实验目的 z 通过编译 JTAG 了解其用法。 z 了解并口(Parallel Port)和 JTAG 之间的关系。 z 了解目标板和并口(Parallel Port)之间的关系。 z 了解 JTAG 在 CPU 中起到什么作用。 z 掌握利用 JTAG 将 Boot Loader 下载到目标板上的方法。 2、 实验设备 z 硬件:PC 机,SinoSys-M3 z 软件:Red Hat9 3、 实验原理 3.1. 几种常用芯片编程方法 在嵌入式系统开发和产品生产过程中,对系统程序存储器编程主要使用三种编程方法, 通过编程器编程、使用板上编程器编程和在系统编程。 1) 通过编程器编程 这是在 PROM、EPROM、PQL 等芯片流行时常用的编程方法。即在可编程芯片焊装到电 路板之前,使用专门的编程器对芯片进行代码或数据的写入,然后将已编程的芯片安装到电 路板上。 使用编程器编程特别适用于 DIP 封装的芯片。如果是其它类型的封装,则必须使用相应 的适配器。这种方法的缺点是要手工进行待编程芯片的插入,锁定等工作,容易造成芯片的 方向错误、引脚错位等,导致编程效率降低。 2) 使用板上编程器编程 (OBP) 这种方法是在电路板上所有的芯片都已经焊接完毕后,再对电路板上的可编程芯片进行 编程。通过专用电缆将电路板与外部计算机连接,由于计算机的应用程序进行板上可编程芯 片的代码或数据写入。芯片擦除编程所需用的电源、控制信号、地址、数据和相关的命令都 由板外的编程控制器提供,在进行板上编程时,需要通过专门的辅助电路关断目标板上 CPU 的电源或将其外部接口信号设置为高阻状态,以免与编程时的地址、数据和控制信号发生冲 突。 在板上编程可以克服芯片引脚错位,方向插反等问题,避免烧毁芯片,编程错误,保证 了芯片编程的高成功率和可靠性。另一个优点就是及时软件升级,可以做到在产品出厂之时 系统使用最新版本的固化软件。这对于日新月异的手持电子设备而言是必须的。 这种方法的缺点是需要在电路板上设计编程用的接口、隔离等辅助电路,在编程时通过 跳线或 FET 开关时进编程与正常工作的状态转换。这样会增加每个电路板芯片的数量,造成 产品成本的增加。 3) 在系统编程(ISP、ISW) 这种方法直接利用系统中带有 JTAG 接口的器件,如 CPU、CPLD、FPGA 等,执行对系 统程序存储芯片的内容的擦除和编程操作。一般而言,高档的微处理器都带有 JTAG 接口, 系统程存储器的数据总线,地址总线和控制接口直接接在微处理器上。编程时,使用 PC 机内 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 84 页 共 175 页 双实科技 插卡或并行的接口通过专用电缆将系统电路板与 PC 机联系起来,在 PC 机上运行相关的程序, 将编程数据及控制信号传送到 JTAG 接口的芯片上,利用相应的指令从微处理器的引脚按照 FLASH 芯片的编程时序输出到 FLASH 存储器。 这种编程方法的条件是系统中必须存在带有 JTAG 接口或与之兼容的芯片如微处理器。 优点是系统板上不需要增加其它于编程有关的辅助电路。减小了电路板的尺寸,避免了对微 小封装芯片的手工处理,特别适用于电路板尺寸有严格限制的手持设备。 3.2. JTAG 接口介绍 面对复杂电路的设计、整板测试的难度及表面的贴装技术带来的有限测试引脚下等问题, 业界不得不寻找一个标准加以解决。JTAG 边界扫描即 IEEE1149.1 标准,该测试标准定义了 用于解决上述问题的硬件结构和工作机制。其优点在于将极其复杂的电路板测试转换成具有 良好的结构性、可以通过软件简单而灵活处理。它虽然是一个主要用于片上电路的测试标准, 但却打开了各种相关应用的大门。这个标准定义了可用于完成功能和互连测试以及内建自测 过程的各种指令。芯片生产厂商如 ALTERA、XILINX、ATMEL、AMD、TI 等对标准进行了 扩充,使用专用的扩展指令执行维护和诊断应用及对可配置器件的可编程算法,使 JTAG 接 口广泛用于 FLASH 系列芯片的编程。概括起来,JTAG 接口主要应用于:电路的边界扫描测 试和可编程芯片的在系统编程。 3.3. JTAG 的结构 在硬件结构上,JTAG 的接口包括两个部分,JTAG 端口和控制器。与 JTAG 接口兼容的 器件可以是微处理器(MPU)微控制器(MCU)PLD CPL FPGA ASIC 或其它符合 IEEE1149.1 规范的芯片。IEEE1149.1 标准中规定对应数字集成电路的每个引脚都设有一个移动寄存单元。 称为边界扫描单元 BSC。它将 JTAG 电路与内核逻辑电路联系起来,同时隔离内核电路和芯 片引脚。由集成电路的所有边界扫描构成单元扫描寄存器 BSR。边界扫描寄存器仅在进行 JTAG 测试时有效,在集成电路工作正常无效,不影响集成电路的功能 。具有 JTAG 接口的 芯片内部结构如图 1 所示: 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 85 页 共 175 页 双实科技 测试逻辑的最高电路包括 3 个主要内容: z 测试访问端口(TAP)控制器 TAP 控制器提供在嵌入在 JTAG 兼容器件内部的测试功能电路的访问控制,是一个同步 状态机。每个 JTAG 兼容的器件都有自己的 TAP 控制器。通过测试模式选择 TMS 和时钟信号 TCK 控制其状态转移,实现由 IEEE149.1 标准确定的测试逻辑电路的工作时序。 z 指令寄存器 指令寄存器是基于电路的移位寄存器,通过它可以串行输入执行各种操作的指令。 z 数据寄存组。 数据寄存器组是一组基于电路的移位寄存器。操作指令被串行装入由当前的指令所选择 的数据寄存器。随着操作的执行,测试结果被移出。 3.4. JTAG 引脚定义 JTAG 接口主要包括四个引脚下:TMS TCK TDI 和 TCO 及一个可选配的引脚 TRST,用 于驱动电路模块和控制执行规定的操作。各引脚的功能如下: z z z z z TCK:JTAG 测试时钟,为 TAP 控制器和寄存器提供测试参考。在 TCK 的同步作用 下通过 TDI 和 TDO 引脚下串行移入或移出数据及指令。同时,TCK 为 TAP 控制器 状态机提供时钟。 TMS:TAP 控制器的三项式输入信号。TCK 的上升沿时刻 TMS 的状态确定 TAP 控 制器即将进入的工作状态。通常 TMS 引脚具有内部上拉电阻 ,以保证该引脚在没 有驱动时处于逻辑 1 状态。 TDI:JTAG 指令和数据寄存器的串行数据输入端。TAP 控制器的当前状态以及保持 在指令寄存器中的具体指令决定对于一个特定的操作由 TDI 装入哪个寄存器。在 TCK 的上升沿时刻,TDI 引脚状态被除数采样,结果送到 JTAG 寄存器组。 TDO:JTAG 指令和数据寄存器的串行输出端。TAP 控制器的当前状态以及保持在指 令寄存器中的具体指令决定对于一个特定的操作哪个寄存器的内容送到 TDO 输出。 对于任何已知的操作,在 TDI 和 TDO 之间只能有一个寄存器(指令或数据)处于有 效连接状态。TDO 在 TCKR 的下降沿改变状态,并且只在数据通过器件移动过程中 有效。该引脚在其它的时间处于三状态下。 TRST:测试复位输入信号,低电平有效,为 TAP 控制器提供异步初始化信号。 3.5. JTAG 测试访问端口(TAP)控制器 TAP 控制器是一个 16 状态的有限状态机,为 JTAG 提供控制逻辑,控制进入到 JTAG 结 构中各种寄存器内数据通信的扫描与操作。TAP 状态转移图如图 2 所示,由 TCK 同步时钟上 升沿时刻 TMS 引脚的逻辑电平决定状态转移的过程, (高电平 TMS=1,低电平 TMS=0)。对 于由 TDI 端输入到器件的扫描信号共有两个状态变化路径:一个用于移入指令到指令寄存器; 另一个用于移入数据到有效的数据寄存器,该寄存器由当前指令确定。 状态图中的每个状态都是通过 TAP 控制器进行数据处理所需要的。这些处理包括给引脚 施加激励信号,捕获输入的数据,装载指令,边界扫描寄存器中数据的移入或移出。图 2 表 示了 TAP 状态机的基本流程,描述了从一个状态到另一个状态 TMS 信号的变化,在芯片 JTAG 接 口 的 TRST 引 脚 上 加 一 个 低 脉 冲 信 号 可 以 使 TAP 控 制 器 复 位 到 测 试 逻 辑 复 位 (Test-Logic-Reset)主状态。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 86 页 共 175 页 双实科技 3.6. JTAG 接口控制指令 控制指令用于控制 JTAG 接口进行各种操作,控制指令包括基本指令和扩展指令。JTAG 接 口 标 准 要 求 芯 片 支 持 的 基 本 指 令 有 : EXTEST INTEST SAMPLE/PRELOAD BYPASS IDCODE HIGHZ。芯片厂商可以根据实际需要选择或添加扩展指令。 3.7. JTAG 接口的使用 通过 JTAG 接口可以进行电路板及芯片的测试,也可以实现对目标电路板上的程序存储 器编程。一般,可以利用专用的 PC 机内插卡式硬件控制器或独立的编程器访问 JTAG 器件。 也可以直接由 PC 机的并行接口模拟 JTAG 时序,硬件控制器或编程器通过专用电缆连接到目 标电路板上,被编程的 FLASH 存储器芯片的地址线,数据线和控制信号线接到 JTAG 兼容芯 片的相应引脚上,如图 3 所示。值得注意的是采用这种编程方法,不要求 FLASH 器件具有 JTAG 接口,只要与其相连接的芯片具有 JTAG 接口即可。在编程 FLASH 芯片时,需要做的工作主 要有: ①PC 机发送指令或数据到 JTAG 兼容芯片的边界扫描寄存器(BSR); ②将保存在 BSR 中的指令或数据通过 JTAG 存储器。这个过程是由运行在 PC 机上的软件进 行控制的。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 87 页 共 175 页 双实科技 4、 实验步骤 4.1. 拷贝 Jflash 原代码到工作目录中 Jflash 的原代码 jflash-s3c2440.tar.gz 在光盘的 SourceCode/Linux/tools 目录中。输入下面命 令拷贝并解压缩。 #mount /mnt/cdrom #mkdir /root/Myjob (如果存在可以省略这一步) #cd /root/Myjob #cp /mnt/cdrom/SourceCode/Linux/tools/jflash-s3c2440.tar.gz /root/Myjob #tar –zxvf jflash-s3c2440.tar.gz 4.2. 编译 Jflash 切换到 JTAG 的源码目录/root/Myjob/Jflash。使用 make 指令编译 JTAG 程序,编译成功 则生成 Jflash-s3c2440 二进制文件。 #cd Jflash #make 请将输入上述指令时做什么动作并生成什么文件简单说明。 4.3. 利用 JTAG 对 Boot Loader 进行烧写 连接好 SinoSys-ICE16。打开实验箱电源。从光盘的 BurnFlash/Linux 把 vivi 拷贝到 Myjob 目录,然后通过 JTAG 从 NAND Flash 0 地址开始进行烧写。如图 4 和图 5 所示。 #cp /mnt/cdrom/BurnFlash/Linux/vivi /root/Myjob/ #cp /root/Myjob/Jflash/Jflash-s3c2440 /root/Myjob #cd /root/Myjob #./Jflash-s3c2440 vivi /t=5 图 4 Jflash-s3c2440 的使用方法 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 88 页 共 175 页 双实科技 图 5 烧写 vivi 中 利用上面编译的 Jflash-s3c2440 将编译好的 boot loader 映像文件 vivi 烧写到 NAND Flash 储存器中。Jflash-s3c2440 程序通过控制与目标板的 JTAG 连接器连接的 host PC 的打印机接口, 对目标板的 boot loader 进行烧写。使用./Jflash-s3c2440 vivi 指令可将 boot loader 烧写到目标板 上。 4.4. 测试刚才烧写进去的 vivi。 关闭实验箱电源。确保启动模式选择开关在 Nand 这边。断开 SinoSys-ICE16,连接串口, 在终端中输入下列命令,按下 PC 的空格键。然后从新开始实验箱的电源, #minicom 这时候应该能从终端 minicom 看到 vivi 输出的信息。如图 6 所示。 图6 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 89 页 共 175 页 双实科技 第三篇 构建嵌入式系统 3.1 编译 BootLoader(uboot) 1、 实验目的 z 了解 BootLoader 的作用和原理 z 编译 vivi 并在 SinoSys-M3 上进行测试 2、 实验设备 z 硬件:PC 机,SinoSys-M3 z 软件:Red Hat9 3、 实验原理 对于计算机系统来说,从开机上电到操作系统启动需要一个引导过程。嵌入式 Linux 系 统同样离不开引导程序,这个引导程序就叫作 Bootloader。 3.1. Bootloader介绍 Bootloader 是在操作系统运行之前执行的一段小程序。通过这段小程序,我们可以初始 化硬件设备、建立内存空间的映射表,从而建立适当的系统软硬件环境,为最终调用操作系 统内核做好准备。 对于嵌入式系统,Bootloader 是基于特定硬件平台来实现的。因此,几乎不可能为所有 的嵌入式系统建立一个通用的 Bootloader,不同的处理器架构都有不同的 Bootloader。 Bootloader 不但依赖于 CPU 的体系结构,而且依赖于嵌入式系统板级设备的配置。对于 2 块 不同的嵌入式板而言,即使它们使用同一种处理器,要想让运行在一块板子上的 Bootloader 程序也能运行在另一块板子上,一般也都需要修改 Bootloader 的源程序。 反过来,大部分 Bootloader 仍然具有很多共性,某些 Bootloader 也能够支持多种体系 结构的嵌入式系统。例如,U-Boot 就同时支持 PowerPC、ARM、MIPS 和 X86 等体系结构,支 持的板子有上百种。通常,它们都能够自动从存储介质上启动,都能够引导操作系统启动, 并且大部分都可以支持串口和以太网接口。 本章将对各种 Bootloader 总结分类,分析它们的共同特点。以 U-Boot 为例,详细讨论 Bootloader 的设计与实现。 3.2. Bootloader的启动 Linux 系统是通过 Bootloader 引导启动的。一上电,就要执行 Bootloader 来初始化系 统。系统加电或复位后,所有 CPU 都会从某个地址开始执行,这是由处理器设计决定的。比 如,X86 的复位向量在高地址端,ARM 处理器在复位时从地址 0x00000000 取第一条指令。嵌 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 90 页 共 175 页 双实科技 入式系统的开发板都要把板上 ROM 或 Flash 映射到这个地址。因此,必须把 Bootloader 程 序存储在相应的 Flash 位置。系统加电后,CPU 将首先执行它。 主机和目标机之间一般有串口可以连接,Bootloader 软件通常会通过串口来输入输出。 例如:输出出错或者执行结果信息到串口终端,从串口终端读取用户控制命令等。 Bootloader 启动过程通常是多阶段的,这样既能提供复杂的功能,又有很好的可移植性。 例如:从 Flash 启动的 Bootloader 多数是两阶段的启动过程。从后面 U-Boot 的内容可以详 细分析这个特性。 大多数 Bootloader 都包含 2 种不同的操作模式:本地加载模式和远程下载模式。这 2 种操作模式的区别仅对于开发人员才有意义,也就是不同启动方式的使用。从最终用户的角 度看,Bootloader 的作用就是用来加载操作系统,而并不存在所谓的本地加载模式与远程下 载模式的区别。 因为 Bootloader 的主要功能是引导操作系统启动,所以我们详细讨论一下各种启动方式 的特点。 1.网络启动方式 种方式开发板不需要配置较大的存储介质,跟无盘工作站有点类似。但是使用这种启动 方式之前,需要把 Bootloader 安装到板上的 EPROM 或者 Flash 中。Bootloader 通过以太网 接口远程下载 Linux 内核映像或者文件系统。这种方式对于嵌入式系统开发来说非常重要。 使用这种方式也有前提条件,就是目标板有串口、以太网接口或者其他连接方式。串口 一般可以作为控制台,同时可以用来下载内核影像和 RAMDISK 文件系统。串口通信传输速率 过低,不适合用来挂接 NFS 文件系统。所以以太网接口成为通用的互连设备,一般的开发板 都可以配置 10M 以太网接口。 对于 PDA 等手持设备来说,以太网的 RJ-45 接口显得大了些,而 USB 接口,特别是 USB 的迷你接口,尺寸非常小。对于开发的嵌入式系统,可以把 USB 接口虚拟成以太网接口来通 讯。这种方式在开发主机和开发板两端都需要驱动程序。 另外,还要在服务器上配置启动相关网络服务。Bootloader 下载文件一般都使用 TFTP 网络协议,还可以通过 DHCP 的方式动态配置 IP 地址。 DHCP/BOOTP 服务为 Bootloader 分配 IP 地址,配置网络参数,然后才能够支持网络传 输功能。如果 Bootloader 可以直接设置网络参数,就可以不使用 DHCP。 TFTP 服务为 Bootloader 客户端提供文 件下 载功能 ,把 内核映 像和 其他文 件放 在 /tftpboot 目录下。这样 Bootloader 可以通过简单的 TFTP 协议远程下载内核映像到内存。如 下图所示。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 91 页 共 175 页 双实科技 大 部 分 引 导 程 序 都 能 够 支 持 网 络 启 动 方 式 。 例 如 : BIOS 的 PXE ( Preboot ExecutionEnvironment)功能就是网络启动方式;U-Boot 也支持网络启动功能。 2.磁盘启动方式 传统的 Linux 系统运行在台式机或者服务器上,这些计算机一般都使用 BIOS 引导,并 且使用磁盘作为存储介质。如果进入 BIOS 设置菜单,可以探测处理器、内存、硬盘等设备, 可以设置 BIOS 从软盘、光盘或者某块硬盘启动。也就是说,BIOS 并不直接引导操作系统。那 么在硬盘的主引导区,还需要一个 Bootloader。这个 Bootloader 可以从磁盘文件系统中把 操作系统引导起来。 Linux 传统上是通过 LILO(LInux LOader)引导的,后来又出现了 GNU 的软件 GRUBGRand Unified Bootloader)。这 2 种 Bootloader 广泛应用在 X86 的 Linux 系统上。你的开发主机 可能就使用了其中一种,熟悉它们有助于配置多种系统引导功能。 LILO 软件工程是由 Werner Almesberger 创建,专门为引导 Linux 开发的。现在 LILO 的 维护者是 John Coffman,最新版本下载站点:http://lilo.go.dyndns.org。LILO 有详细的 文档,例如 LILO 套件中附带使用手册和参考手册。此外,还可以在 LDP 的“LILO mini-HOWTO” 中找到 LILO 的使用指南。 GRUB 是 GNU 计划的主要 bootloader。GRUB 最初是由 Erich Boleyn 为 GNU Mach 操作系统 撰写的引导程序。后来有 Gordon Matzigkeit 和 Okuji Yoshinori 接替 Erich 的工作,继续 维护和开发 GRUB。GRUB 的网站 http://www.gnu.org/software/grub/上有对套件使用的说明 文件,叫作《GRUB manual》。GRUB 能够使用 TFTP 和 BOOTP 或者 DHCP 通过网络启动,这种功 能对于系统开发过程很有用。 除了传统的 Linux 系统上的引导程序以外,还有其他一些引导程序,也可以支持磁盘引 导启动。例如:LoadLin 可以从 DOS 下启动 Linux;还有 ROLO、LinuxBIOS,U-Boot 也支持 这种功能。 3.Flash 启动方式 大多数嵌入式系统上都使用 Flash 存储介质。Flash 有很多类型,包括 NOR Flash、 NANDFlash 和其他半导体盘。其中,NOR Flash(也就是线性 Flash)使用最为普遍。 NOR Flash 可以支持随机访问,所以代码是可以直接在 Flash 上执行的。Bootloader 一 般是存储在 Flash 芯片上的。另外,Linux 内核映像和 RAMDISK 也可以存储在 Flash 上。通 常需要把 Flash 分区使用,每个区的大小应该是 Flash 擦除块大小的整数倍。下图是 Bootloader 和内核映像以及文件系统的分区表。 Bootloader 一般放在 Flash 的底端或者顶端,这要根据处理器的复位向量设置。要使 Bootloader 的入口位于处理器上电执行第一条指令的位置。 接下来分配参数区,这里可以作为 Bootloader 的参数保存区域。 再下来内核映像区。Bootloader 引导 Linux 内核,就是要从这个地方把内核映像解压到 RAM 中去,然后跳转到内核映像入口执行。 然后是文件系统区。如果使用 Ramdisk 文件系统,则需要 Bootloader 把它解压到 RAM 中。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 92 页 共 175 页 双实科技 如果使用 JFFS2 文件系统,将直接挂接为根文件系统。这两种文件系统将在第 12 章详细讲解。 最后还可以分出一些数据区,这要根据实际需要和 Flash 大小来考虑了。 这些分区是开发者定义的,Bootloader 一般直接读写对应的偏移地址。到了 Linux 内核 空间,可以配置成 MTD 设备来访问 Flash 分区。但是,有的 Bootloader 也支持分区的功能, 例如:Redboot 可以创建 Flash 分区表,并且内核 MTD 驱动可以解析出 redboot 的分区表。 除了 NOR Flash,还有 NAND Flash、Compact Flash、DiskOnChip 等。这些 Flash 具有芯 片价格低,存储容量大的特点。但是这些芯片一般通过专用控制器的 I/O 方式来访问,不能 随机访问,因此引导方式跟 NOR Flash 也不同。在这些芯片上,需要配置专用的引导程序。 通常,这种引导程序起始的一段代码就把整个引导程序复制到 RAM 中运行,从而实现自举启 动,这跟从磁盘上启动有些相似。 3.3. Bootloader的种类 嵌入式系统世界已经有各种各样的 Bootloader,种类划分也有多种方式。除了按照处理 器体系结构不同划分以外,还有功能复杂程度的不同。 首先区分一下“Bootloader”和“Monitor”的概念。严格来说,“Bootloader”只是引 导设备并且执行主程序的固件;而“Monitor”还提供了更多的命令行接口,可以进行调试、 读写内存、烧写 Flash、配置环境变量等。 “Monitor”在嵌入式系统开发过程中可以提供很好 的调试功能,开发完成以后,就完全设置成了一个“Bootloader” 。所以,习惯上大家把它们 统称为 Bootloader。 表 6.1 列出了 Linux 的开放源码引导程序及其支持的体系结构。表中给出了 X86 ARMPowerPC 体系结构的常用引导程序,并且注明了每一种引导程序是不是“Monitor”。 对于每种体系结构,都有一系列开放源码 Bootloader 可以选用。 (1)X86 X86 的 工 作 站 和 服 务 器 上 一 般 使 用 LILO 和 GRUB 。 LILO 是 Linux 发 行 版 主 流 的 Bootloader。不过 Redhat Linux 发行版已经使用了 GRUB,GRUB 比 LILO 有更有好的显示界面, 使用配置也更加灵活方便。 在某些 X86 嵌入式单板机或者特殊设备上,会采用其他 Bootloader,例如:ROLO。这些 Bootloader 可以取代 BIOS 的功能,能够从 FLASH 中直接引导 Linux 启动。现在 ROLO 支持 的开发板已经并入 U-Boot,所以 U-Boot 也可以支持 X86 平台。 (2)ARM 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 93 页 共 175 页 双实科技 ARM 处理器的芯片商很多,所以每种芯片的开发板都有自己的 Bootloader。结果 ARM bootloader 也变得多种多样。最早有为 ARM720 处理器的开发板的固件,又有了 armboot, StrongARM 平台的 blob,还有 S3C2410 处理器开发板上的 vivi 等。现在 armboot 已经并入了 U-Boot,所以 U-Boot 也支持 ARM/XSCALE 平台。U-Boot 已经成为 ARM 平台事实上的标准 Bootloader。 (3)PowerPC PowerPC 平台的处理器有标准的 Bootloader,就是 ppcboot。PPCBOOT 在合并 armboot 等之后,创建了 U-Boot,成为各种体系结构开发板的通用引导程序。U-Boot 仍然是 PowerPC 平台的主要 Bootloader。 (4)MIPS MIPS 公司开发的 YAMON 是标准的 Bootloader,也有许多 MIPS 芯片商为自己的开发板写 了 Bootloader。现在,U-Boot 也已经支持 MIPS 平台。 (5)SH SH 平台的标准 Bootloader 是 sh-boot。Redboot 在这种平台上也很好用。 (6)M68K M68K 平台没有标准的 Bootloader。Redboot 能够支持 m68k 系列的系统。 值得说明的是 Redboot,它几乎能够支持所有的体系结构,包括 MIPS、SH、M68K 等体系 结构。Redboot 是以 eCos 为基础,采用 GPL 许可的开源软件工程。现在由 core eCos 的开发 人员维护,源码下载网站是 http://www.ecoscentric.com/snapshots。Redboot 的文档也相 当完善,有详细的使用手册《RedBoot User’s Guide》。 3.4. U-Boot源码结构 从网站上下载得到 U-Boot 源码包,例如:U-Boot-1.2.0.tar.bz2 解压就可以得到全部 U-Boot 源程序。在顶层目录下有 18 个子目录,分别存放和管理不 同的源程序。这些目录中所要存放的文件有其规则,可以分为 3 类。 • 第 1 类目录与处理器体系结构或者开发板硬件直接相关; • 第 2 类目录是一些通用的函数或者驱动程序; • 第 3 类目录是 U-Boot 的应用程序、工具或者文档。 表6.2 列出了 U-Boot 顶层目录下各级目录存放原则。 目 录 特 性 board 平台依赖 cpu 平台依赖 lib_ppc 平台依赖 目 特 录 性 解 释 说 明 存放电路板相关的目录文件,例如:RPXlite(mpc8xx)、smdk2410(arm920 t)、sc520_cdp(x86) 等目录 存放 CPU 相关的目录文件,例如:mpc8xx、ppc4xx、arm720t、arm920t、 xscale、i386 等目录 存放对 PowerPC 体系结构通用的文件,主要用于实现 PowerPC 平台通用的 函数 解 释 说 明 lib_arm 平台依赖 存放对 ARM 体系结构通用的文件,主要用于实现 ARM 平台通用的函数 lib_i386 平台依赖 存放对 X86 体系结构通用的文件,主要用于实现 X86 平台通用的函数 include 通用 头文件和开发板配置文件,所有开发板的配置文件都在 configs 目录下 common 通用 通用的多功能函数实现 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 94 页 共 175 页 双实科技 lib_generic 通用 通用库函数的实现 Net 通用 存放网络的程序 Fs 通用 存放文件系统的程序 Post 通用 存放上电自检程序 drivers 通用 通用的设备驱动程序,主要有以太网接口的驱动 Disk 通用 硬盘接口程序 Rtc 通用 RTC 的驱动程序 Dtt 通用 数字温度测量器或者传感器的驱动 examples 应用例程 一些独立运行的应用程序的例子,例如 helloworld tools 工具 存放制作 S-Record 或者 U-Boot 格式的映像等工具,例如 mkimage Doc 文档 开发使用文档 U-Boot 的源代码包含对几十种处理器、数百种开发板的支持。可是对于特定的开发板, 配置编译过程只需要其中部分程序。这里具体以 S3C2440 arm920t 处理器为例,具体分析 S3C2440 处理器和开发板所依赖的程序,以及 U-Boot 的通用函数和工具。 4、 实验步骤 4.1. 编译 U-Boot 进入 U-Boot 代码目录 #cd u-boot1.2.0 进行配置 #make smdk2440_config 进行编译 #make 然后就会在/u-boot1.2.0 目录下生成 u-boot.bin 4.2. 烧写 U-Boot 到 Nand Flash 利用仿真器 ICE16 通过 JTAG 口,把 U-Boot 下载到开发板。(具体的操作方法见实验 2.8)) #./Jflash-s3c2440 u-boot.bin /t=5 4.3. U-Boot 的常用命令的学习 1、 启动 U-Boot 给开发板上电,U-Boot 启动,从串口中打印出以下信息,此时,敲任意键退出自动启动 状态,进入命令行。 U-Boot 1.1.2 (Apr 26 2005 - 12:27:13) U-Boot code: 11080000 -> 1109614C BSS: -> 1109A91C RAM Configuration: 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 95 页 共 175 页 双实科技 Bank #0: 10000000 32 MB Micron StrataFlash MT28F128J3 device initialized Flash: 32 MB In: serial Out: serial Err: serial Hit any key to stop autoboot: 0 U-Boot> 在命令行提示符下,可以输入 U-Boot 的命令并执行。U-Boot 可以支持几十个常用命令, 通过这些命令,可以对开发板进行调试,可以引导 Linux 内核,还可以擦写 Flash 完成系统 部署等功能。掌握这些命令的使用,才能够顺利地进行嵌入式系统的开发。 2、 浏览 U-Boot 所包含的命令 输入 help 命令,可以得到当前 U-Boot 的所有命令列表。每一条命令后面是简单的命令 说明。 => help ? - alias for 'help' autoscr - run script from memory base - print or set address offset bdinfo - print Board Info structure boot - boot default, i.e., run 'bootcmd' bootd - boot default, i.e., run 'bootcmd' bootm - boot application image from memory bootp - boot image via network using BootP/TFTP protocol cmp - memory compare coninfo - print console devices and information cp - memory copy crc32 - checksum calculation dhcp - invoke DHCP client to obtain IP/boot params echo - echo args to console erase - erase FLASH memory flinfo - print FLASH memory information go - start application at address 'addr' help - print online help iminfo - print header information for application image imls - list all images found in flash itest - return true/false on integer compare loadb - load binary file over serial line (kermit mode) loads - load S-Record file over serial line loop - infinite loop on address range md - memory display mm - memory modify (auto-incrementing) mtest - simple RAM test 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 96 页 共 175 页 双实科技 mw - memory write (fill) nfs - boot image via network using NFS protocol nm - memory modify (constant address) printenv - print environment variables protect - enable or disable FLASH write protection rarpboot - boot image via network using RARP/TFTP protocol reset - Perform RESET of the CPU run - run commands in an environment variable saveenv - save environment variables to persistent storage setenv - set environment variables sleep - delay execution for some time tftpboot - boot image via network using TFTP protocol version - print monitor version => U-Boot 还提供了更加详细的命令帮助,通过 help 命令还可以查看每个命令的参数说明。 由于开发过程的需要,有必要先把 U-Boot 命令的用法弄清楚。例如你想知道 bootm 命令的相 关信息: => help bootm bootm [addr [arg ...]] - boot application image stored in memory passing arguments 'arg ...'; when booting a Linux kernel, 'arg' can be the address of an initrd imag e 3、 学习 U-Boot 的几个常用的命令 根据每一条命令的帮助信息,说明这些命令的功能、参数和用法。 z bootm => help bootm bootm [addr [arg ...]] - boot application image stored in memory passing arguments 'arg ...'; when booting a Linux kernel, 'arg' can be the address of an initrd image bootm 命令可以引导启动存储在内存中的程序映像。这些内存包括 RAM 和可以永久保 存的 Flash。 第 1 个参数 addr 是程序映像的地址,这个程序映像必须转换成 U-Boot 的格式。 第 2 个参数对于引导 Linux 内核有用,通常作为 U-Boot 格式的 RAMDISK 映像存储地 址;也可以是传递给 Linux 内核的参数(缺省情况下传递 bootargs 环境变量给内核)。 例如: bootm 0x300000 —— 从内存地址 0x300000 启动 z cp => help cp cp [.b, .w, .l] source target count - copy memory 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 97 页 共 175 页 双实科技 cp 命令可以在内存中复制数据块,包括对 Flash 的读写操作。 第 1 个参数 source 是要复制的数据块起始地址。 第 2 个参数 target 是数据块要复制到的地址。这个地址如果在 Flash 中,那么会直接调用 写 Flash 的函数操作。所以 U-Boot 写 Flash 就使用这个命令,当然需要先把对应 Flash 区域擦 干净。 第 3 个参数 count 是要复制的数目,根据 cp.b cp.w cp.l 分别以字节、字、长字为单位。 例如: cp.b 0x300000 0xFE040000 0x180000 将 1.5M 数据从内存拷到 flash 0xFE040000 位置。 z loadb => help loadb loadb [ off ] [ baud ] - load binary file over serial line with offset 'off' and baudrate 'baud' loadb 命令可以通过串口线下载二进制格式文件。 z printenv => help printenv printenv - print values of all environment variables printenv name ... - print value of environment variable 'name' printenv 命令打印环境变量。可以打印全部环境变量,也可以只打印参数中列出的环境变 量。 z setenv => help setenv setenv name value ... - set environment variable 'name' to 'value ...' setenv name - delete environment variable 'name' setenv 命令可以设置环境变量。 第 1 个参数是环境变量的名称。 第 2 个参数是要设置的值,如果没有第 2 个参数,表示删除这个环境变量。 例如: => set ipaddr 192.168.1.20 —— 设置设备地址为 192.168.1.20 z tftpboot => help tftpboot tftpboot [loadAddress] [bootfilename] tftpboot 命令可以使用 TFTP 协议通过网络下载文件。按照二进制文件格式下载。另外使 用这个命令,必须配置好相关的环境变量。例如 serverip 和 ipaddr。 第 1 个参数 loadAddress 是下载到的内存地址。 第 2 个参数是要下载的文件名称,必须放在 TFTP 服务器相应的目录下。 例如: 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 98 页 共 175 页 双实科技 => tftpboot 0x300000 uImage —— 设置从 TFTP server 上取 uImage 到内存地址 0x300000 4.4. 修改启动参数,启动内核 主要是修改环境变量:bootargs 与 bootcmd,实现自动从 NAND Flash 中复制内核,启动 内核. => setenv bootargs root=/dev/mtdblock2 init=/linuxrc console=ttySAC0,115200 设置 Linux 内核启动的命令行参数。 => setenv bootcmd nand read 0x31000000 0x30000 0x1d0000;bootm 0x31000000 设置 U-Boot 启动运行命令:启动时,从 Flash 中读取内核,,然后执行 bootm 命令,启动 Linux 内核,以实现 Linux 系统的自动启动。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 99 页 共 175 页 双实科技 3.2 编译嵌入式 Linux 内核 1、 实验目的 z 了解 Linux 内核结构 z 编译内核并在 SinoSys-M3 上进行测试 2、 实验设备 z 硬件:PC 机,SinoSys-M3 z 软件:Red Hat9 3、 实验原理 3.1. Linux 简介 简单地说,Linux 是一套免费使用和自由传播的类 Unix 操作系统,是一个基于 POSIX 和 UNIX 的多用户、多任务、支持多线程和多 CPU 的操作系统。它能运行主要的 UNIX 工具软 件、应用程序和网络协议。它支持 32 位和 64 位硬件。Linux 继承了 Unix 以网络为核心的设 计思想,是一个性能稳定的多用户网络操作系统。它主要用于基于 Intel x86 系列 CPU 的计算 机上。这个系统是由全世界各地的成千上万的程序员设计和实现的。其目的是建立不受任何 商品化软件的版权制约的、全世界都能自由使用的 Unix 兼容产品! Linux 以它的高效性和灵活性著称。Linux 模块化的设计结构,使得它既能在价格昂贵的 工作站上运行,也能够在廉价的 PC 机上实现全部的 Unix 特性,具有多任务、多用户的能力。 Linux 是在 GNU 公共许可权限下免费获得的,是一个符合 POSIX 标准的操作系统。 3.2. linux 系统结构 linux 系统由 4 个部分构成,如图 1 所示: P P P P P System Call Interface(POSIX.1),shell,GUICompiler,Library,etc. Linux Kernel Linux内核层 Device Driver Interface Device Drivers OS服务层 Module Interface Modules 用户进程 Other Devices CPU Disk 硬件层 图1 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 100 页 共 175 页 双实科技 z z z z 用户应用程序—在某个特定的 Linux 系统上运行的应用程序集合,它将随着该计算 机系统的用途不同而有所变化,如文字处理应用程序、Web 浏览器。 O/S 服务—这些服务一般认为是操作系统的一部分(窗口系统,命令外壳程序等); 此外,内核的编程接口(编译工具和库)也属于这个子系统。 Linux 内核—包括内核抽象和对硬件资源(如 CPU)的间接访问。 硬件控制器—这个子系统包含在 Linux 实现中所有可能的物理设备,例如,CPU、 内存硬件、硬盘以及网络硬件等都是这个系统的成员。 3.3. linux 内核组成: Linux 内核主要由五个子系统组成:进程调度,内存管理,虚拟文件系统,网络接口,进 程间通信。如图 2 所示 图2 1.进程调度(SCHED):控制进程对 CPU 的访问。当需要选择下一个进程运行时,由调度 程序选择最值得运行的进程。可运行进程实际上是仅等待 CPU 资源的进程,如果某个进程在 等待其它资源,则该进程是不可运行进程。Linux 使用了比较简单的基于优先级的进程调度算 法选择新的进程。 2.内存管理(MM)允许多个进程安全的共享主内存区域。Linux 的内存管理支持虚拟内 存,即在计算机中运行的程序,其代码,数据,堆栈的总量可以超过实际内存的大小,操作 系统只是把当前使用的程序块保留在内存中,其余的程序块则保留在磁盘中。必要时,操作 系统负责在磁盘和内存间交换程序块。内存管理从逻辑上分为硬件无关部分和硬件有关部分。 硬件无关部分提供了进程的映射和逻辑内存的对换;硬件相关的部分为内存管理硬件提供了 虚拟接口。 3.虚拟文件系统(VirtualFileSystem,VFS)隐藏了各种硬件的具体细节,为所有的设备提 供了统一的接口,VFS 提供了多达数十种不同的文件系统。虚拟文件系统可以分为逻辑文件 系统和设备驱动程序。逻辑文件系统指 Linux 所支持的文件系统,如 ext2,fat 等,设备驱动程 序指为每一种硬件控制器所编写的设备驱动程序模块。 4.网络接口(NET)提供了对各种网络标准的存取和各种网络硬件的支持。网络接口可分 为网络协议和网络驱动程序。网络协议部分负责实现每一种可能的网络传输协议。网络设备 驱动程序负责与硬件设备通讯,每一种可能的硬件设备都有相应的设备驱动程序。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 101 页 共 175 页 双实科技 5.进程间通讯(IPC) 支持进程间各种通信机制。 处于中心位置的进程调度,所有其它的子系统都依赖它,因为每个子系统都需要挂起或 恢复进程。一般情况下,当一个进程等待硬件操作完成时,它被挂起;当操作真正完成时, 进程被恢复执行。例如,当一个进程通过网络发送一条消息时,网络接口需要挂起发送进程, 直到硬件成功地完成消息的发送,当消息被成功的发送出去以后,网络接口给进程返回一个 代码,表示操作的成功或失败。其他子系统以相似的理由依赖于进程调度。 各个子系统之间的依赖关系如下: 进程调度与内存管理之间的关系:这两个子系统互相依赖。在多道程序环境下,程序要 运行必须为之创建进程,而创建进程的第一件事情,就是将程序和数据装入内存。 进程间通信与内存管理的关系:进程间通信子系统要依赖内存管理支持共享内存通信机制, 这种机制允许两个进程除了拥有自己的私有空间,还可以存取共同的内存区域。 虚拟文件系统与网络接口之间的关系:虚拟文件系统利用网络接口支持网络文件系统(NFS), 也利用内存管理支持 RAMDISK 设备。 内存管理与虚拟文件系统之间的关系:内存管理利用虚拟文件系统支持交换,交换进程 (swapd)定期由调度程序调度,这也是内存管理依赖于进程调度的唯一原因。当一个进程存取 的内存映射被换出时,内存管理向文件系统发出请求,同时,挂起当前正在运行的进程。 除了这些依赖关系外,内核中的所有子系统还要依赖于一些共同的资源。这些资源包括所有 子系统都用到的过程。例如:分配和释放内存空间的过程,打印警告或错误信息的过程,还 有系统的调试例程等等。 3.4. linux 内核源码目录结构 在阅读源码之前,还应知道 Linux 内核源码的整体分布情况。现代的操作系统一般由进 程管理、内存管理、文件系统、驱动程序和网络等组成。Linux 内核源码的各个目录大致与此 相对应,其组成如下(假设相对于 Linux-2.4.x 目录): arch:arch 目录包括了所有和体系结构相关的核心代码。它下面的每一个子目录都代表一 种 Linux 支持的体系结构,例如 i386 就是 Intel CPU 及与之相兼容体系结构的子目录。PC 机 一般都基于此目录。 include:include 目录包括编译核心所需要的大部分头文件,例如与平台无关的头文件在 include/linux 子目录下。 init:init 目录包含核心的初始化代码(不是系统的引导代码),有 main.c 和 Version.c 两 个文件。这是研究核心如何工作的好起点。 mm:mm 目录包含了所有的内存管理代码。与具体硬件体系结构相关的内存管理代码位 于 archkernel 目录下。 net:net 目录里是核心的网络部分代码,其每个子目录对应于网络的一个方面。 lib:lib 目录包含了核心的库代码,不过与处理器结构相关的库代码被放在 arch/*/lib/目录 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 102 页 共 175 页 双实科技 下。 scripts:scripts 目录包含用于配置核心的脚本文件。 documentation:documentation 目录下是一些文档,是对每个目录作用的具体说明。 一般在每个目录下都有一个.depend 文件和一个 Makefile 文件。这两个文件都是编译时使 用的辅助文件。仔细阅读这两个文件对弄清各个文件之间的联系和依托关系很有帮助。另外 有的目录下还有 Readme 文件,它是对该目录下文件的一些说明,同样有利于对内核源码的理 解。 3.5. 嵌入式 Linux 应用领域 对于桌面系统,微软的 Windows 有着强劲的优势,不要期望一般的 PC 用户很快转向使 用 Linux。但在嵌入式及实时应用中,操作系统是不可见的、隐藏的技术,只对应用提供相关 的支持,诸如一个非电脑设备。对于用户更乐于使用嵌入式 Linux 的应用产品,而不是使用 Linux。对于系统开发者而言,Linux 如下的特点是选择的关键: z z z z z 源代码可自由获得。 无单个产品的版权费。 支持大量的硬件设备。 Linux 已经是一个全球性的标准。 Linux 是一个成熟的、高效的、健壮的、可靠的、模块化的、非常易于配置的操作系 统。 嵌入式 Linux 已经不可逆转地改变了嵌入式实时操作系统的市场前景。开发者拥有了对 他们的嵌入式操作系统更好的控制权;制造商则在成本以及令人头痛的单一产品版权费问题 上获得前所未有的收益,而最终用户则可得到更有价值的且价格较低的产品。 4、 实验步骤 4.1. 拷贝 kernel 源代码到工作目录中 kernel 的源代码 linux-2.6.26.tar.bz2 在光盘的/SourceCode/Linux/kernel/目录中。输入下面 命令拷贝并解压缩。 #mount /mnt/cdrom #mkdir /root/Myjob (如果存在可以省略这一步) #cd /root/Myjob #cp /mnt/cdrom/SourceCode/Linux/kernel/ linux-2.6.262 /root/Myjob #tar –jxvf linux-2.6.26 4.2. 进入 linux-2.6.26 并且编译 #cd linux-2.6.26 #make distclean #make menuconfig 此时会看到如图 3 的界面: 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 103 页 共 175 页 双实科技 图3 选择“Load an Alternate Configuration File”菜单载入配置文件,然后在输入框写 入“arch/arm/def-configs/smdk2440”。如图 4 所示。 图4 选择“OK”。 打开菜单的各个页,查看配置文件的默认选项,图 6 为其中的 File Systems 菜单的默认 选项。可以用空格键或回车来改变选项。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 104 页 共 175 页 双实科技 图6 选择“Exit” ,然后选择“Yes”退出。 配置完毕后,保存退出。执行下面的命令来生成内核映像。 4.3. 运行 make 编译 #make uImage 映像文件产生在/arch/arm/boot/目录下,名称“uImage”。 4.4. 利用 U-Boot 通过网口对 uImage 进行烧写 连接上网线,在 PC 上打开 tftp 服务,设置好 tftp 服务器。打开开发板的电源 按任意键,使 UBoot 进入命令行模式: =>tftp 0x31000000 uImage =>nand erase 0x30000 0x200000 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 105 页 共 175 页 双实科技 =>nand write 0x31000000 0x30000 0x1d0000 4.5. 测试刚才烧写进去的 Linux 内核。 复位一下开发板, 这时候应该能从终端 minicom 看到 uboot 及内核输出的信息。如 图 7 所示。 图7 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 106 页 共 175 页 双实科技 3.3 构建嵌入式 Linux 文件系统 1、 实验目的 z 了解 Linux 文件系统的结构 z 了解 BusyBox 的实现机理 z 编译 BusyBox 并构建嵌入式 linux 根文件系统 2、 实验设备 z 硬件:PC 机,SinoSys-M3 z 软件:Red Hat9 3、 实验原理 3.1. 简介文件系统 文件系统是指在一个物理设备上的任何文件组织和目录,它构成了 Linux 系统上所有数 据的基础,Linux 程序、库、系统文件和用户文件都驻留其中,因此,它是系统中庞大复杂且 又是最为基本和重要的资源。值得提出的是,Linux 系统中的文件不仅包括普通的文件和目录, 每个和设备相关的实际实体也都被映射为一个文件,例如磁盘、打印机、终端等等,这样的 设备文件又称为特殊文件。所以,Linux 下的文件是操作系统服务和设备的简单而又统一的接 口,从某种意义上可以说,Linux 里的一切事物都是文件。 由于 Linux 是一个多任务、多用户的操作系统,因此它里面的文件还都被赋予了一定的 权限,权限决定谁能读、写或执行一个文件,以及这个文件的类型和如何执行。例如下面的 文件列表: -rw-r--r-- 1 root root 1756 Sep 4 2002 inittab 就表示:这个名为 inittab 的文件是普通文件,所有者有读写的权限,所在组和其他人都 只有读的权限,它的连接数为 1,所有者及文件所属的组都是 root,文件中字节数为 1756, 文件创建日期是 2002 年 9 月 4 日。我们可以通过对文件属性的设置,来满足文件在不同用户 组、不同用户操作下的不同状态。 3.2. 文件系统的结构 在 Linux 中,文件系统的结构是基于树状的,根在顶部,各个目录和文件从树根向下分 支,目录树的最顶端被称为根目录(/)。Linux 操作系统由一些目录和许多文件组成,例如, 图中的/bin 目录包含二进制文件的可执行程序,/sbin 目录用于存储管理系统的二进制文件,/etc 目录包含绝大部分的 Linux 系统配置文件,/lib 目录存储程序运行时使用的共享库,/dev 目录 包含称为设备文件的特殊文件,/proc 目录实际上是一个虚拟文件系统,/tmp 目录用于存储程 序运行时生成的临时文件,/home 目录是用户起始目录的基础目录,/var 目录保存要随时改变 大小的文件,/usr 目录及其子目录对 Linux 系统的操作非常重要,它保存着系统上的一些最 重要的程序以及包含你安装的大型软件包。表 1 是在 RedHat Linux 文件系的结构。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 107 页 共 175 页 双实科技 表 1 RedHat Linux 文件系结构 / Linux 系统根目录 /bin Binary 的缩写,存放用户的可执行程序,例如 ls,cp,也包含其它的 SHELLR 如:bash 等 /boot 包含 vmlinuz,initrd.img 等启动文件,随便改动可能无法正常开机哦 /dev 接口设备文件目录,如你的硬盘:hda /etc passwd 这样有关系统设置与管理的文件 /etc/x11 X Windows System 的设置目录 /home 一般用户的主目录,如 FTP 目录等 /lib 包含执行/bin 和/sbin 目录的二进制文件时所需的共享函数库 library /mnt 各项装置的文件系统加载点,例如:/mnt/cdrom 是光驱的加载点 /opt 提供空间,叫较大的且固定的应用程序存储文件之用 /proc PS 命令查询的信息与这里的相同,都是系统内核与程序执行的信息 /root 管理员的主目录 /sbin lilo 等系统启动时所需的二进制程序 /tmp Temporary,存放暂存盘的目录 /usr 存放用户使用系统命令和应用程序等信息 /usr/bin 存放用户可执行程序,如 grep,mdir 等 /usr/doc 存放各式程序文件的目录 /usr/include 保存提供 C 语言加载的 header 文件 /usr/include/X11 保存提供 X Windows 程序加载的 header 文件 /usr/info GNU 程序文件目录 /usr/lib 函数库 /usr/lib/X11 函数库 /usr/local 提供自行安装的应用程序位置 /usr/man 存放在线说明文件目录 /usr/sbin 存放经常使用的程序,如 showmount /usr/src 保存程序的原始文件 /usr/X11R6/bin 存放 X Windows System 的执行程序 /var Variable,具有变动性质的相关程序目录,如 log 3.3. BusyBox 的诞生 BusyBox 最初是由 Bruce Perens 在 1996 年为 Debian GNU/Linux 安装盘编写的。其目 标是在一张软盘上创建一个可引导的 GNU/Linux 系统,这可以用作安装盘和急救盘。一张 软盘可以保存大约 1.4-1.7MB 的内容,因此这里没有多少空间留给 Linux 内核以及相关的用 户应用程序使用。 BusyBox 是按照 GNU General Public License(GPL)许可证发行的。这意味着如果我们 在一个项目中使用 BusyBox,就必须遵守这个许可证。我们可以在 BusyBox Web 站点(请 参看本文后面 参考资料 一节的内容)上看到这个许可证的内容。BusyBox 团队似乎正忙于 监视违反这个许可证的情况。实际上,他们维护了一个 “Hall of Shame” 页面来说明违反者 的情况。 BusyBox 揭露了这样一个事实:很多标准 Linux 工具都可以共享很多共同的元素。例如, 很多基于文件的工具(比如 grep 和 find)都需要在目录中搜索文件的代码。当这些工具被 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 108 页 共 175 页 双实科技 合并到一个可执行程序中时,它们就可以共享这些相同的元素,这样可以产生更小的可执行 程序。实际上, BusyBox 可以将大约 3.5MB 的工具包装成大约 200KB 大小。这就为可引 导的磁盘和使用 Linux 的嵌入式设备提供了更多功能。我们可以对 2.4 和 2.6 版本的 Linux 内核使用 BusyBox。 3.4. BusyBox 简介 熟悉嵌入式 Linux 的人对 busybox 一定不会陌生。它被非常形象地称为嵌入式 Linux 系统 中的“瑞士军刀”,因为它将许多常用的 UNIX 命令和工具结合到了一个单独的可执行程序中。 虽然与相应的 GNU 工具比较起来,busybox 所提供的功能和参数略少,但在比较小的系统(例 如启动盘)或者嵌入式系统中,已经足够了。 busybox 在设计上就充分考虑了硬件资源受限的特殊工作环境。它采用一种很巧妙的办法 减少自己的体积:所有的命令都通过“插件”的方式集中到一个可执行文件中,在实际应用过 程中通过不同的符号链接来确定到底要执行哪个操作。例如最终生成的可执行文件为 busybox, 当为它建立一个符号链接 ls 的时候,就可以通过执行这个新命令实现列目录的功能。采用单一 执行文件的方式最大限度地共享了程序代码,甚至连文件头、内存中的程序控制块等其他操作 系统资源都共享了,对于资源比较紧张的系统来说,真是最合适不过了。 在 busybox 的编译过程中,可以非常方便地加减它的“插件”,最后的符号链接也可以由编 译系统自动生成。 3.5. 完善文件系统 参考一个正常的 Linux 系统就会发现,busybox 建立的文件系统还缺少很多文件,其中包 括 prot 等重要的文件夹。下面三行命令建立了常见 UNIX 系统中包含的一些目录,虽然它们不 全是必需的,但建立它们更符合标准一些。这些命令都是在新文件系统的根目录中执行的,第三 条命令的执行还必须要有 root 权限。 mkdir mnt root var tmp proc boot etc lib chown 0:0R * 如 果 busybox 采 用 了 动 态 链 接 的 方 式 编 译 , 还 需 要 把 busybox 所 需 要 的 动 态 库 : libcrypt.so.1、libc.so.6、ldlinux.so.2 放到 lib 目录中。最好按照标准的方式建立相应的文件和 链接,可以参考下面的列表: -rwxrwxrwx 192519ld-2.3.2.so lrwxrwxrwx 111ld-linux.so.2 -> ld-2.3.2.so -rwxrwxrwx 1 1190032libc-2.3.2.so lrwxrwxrwx 113libc.so.6 -> libc-2.3.2.so -rwxr-xr-x 118348libcrypt-2.3.2.so lrwxrwxrwx 117libcrypt.so.1 -> libcrypt-2.3.2.so 这里需要说明的是,虽然 BusyBox 只使用了这三个库文件,但我们并不能保证往后向文 件系统添加的应用程序只使用这三个库文件,其中典型的,C++的库文件这里就没有。 库文件的添加是构造嵌入式 linux 根文件系统中最耗时,最头疼的事情。同时,它也是嵌入式 文件系统中体积最大的文件。因此,嵌入式系统中一般使用精简过的 C 库。同时,我们也就 想尽办法去掉一些没有的库。要知道我们的应用程序需要什么库文件,可以在目标系统中使 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 109 页 共 175 页 双实科技 用 ldd 命令。 3.6. 编写 etc 目录下的文件 etc 文件夹是许多系统配置文件保存的地方。这些文件非常重要,如果配置错误,就可能影 响系统的启动。busybox 源代码 example/bootfloopy/etc 目录中的文件算是一个简单的例子,可 以把其中的文件拷贝过来作为基础。 (在 example/bootfloopy 目录中的一些脚本和文档也很值 得阅读) 首先 inittab 文件是系统启动后所访问的第一个脚本文件,后续启动的文件都由它指定。这 个文件的格式和普通微机 Linux 上的 inittab 是有区别的,其具体含义可以参考 busybox 的文档。 下面是一个比较简单的例子: ::sysinit:/etc/init.d/rcS ::ctrlaltdel:/sbin/reboot ::shutdown:/bin/umount ar ::shutdown:/bin/mount / o remount,ro 其中第一行指定了系统的启动脚本为/etc/init.d/rcS;第二行指定在第一个虚拟终端打开一 个登录会话;第三行指定在第三个虚拟终端打开一个无须登录验证的 shell;第四行指定了当按 下 ctrl+alt+del 组合键时的执行命令;最后两行指定了关机时执行的操作。 fstab 文件定义了文件系统的各个“挂接点”,需要与实际的系统相配合。一个简单的 fstab 文件如下: proc/procprocdefaults00 /dev/hda1/ext2rw,noauto01 devpts/dev/ptsdevptsdefaults00 4、 实验步骤 4.1. 拷贝 busybox 源代码到工作目录中 busybox 的源代码 busybox-1.1.0.tar.bz2 在光盘的 SourceCode/Linux/tools 目录中。输入下 面命令拷贝并解压缩。 #mount /mnt/cdrom #mkdir /root/Myjob (如果存在可以省略这一步) #mkdir /root/Myrootfs #cd /root/Myjob #cp /mnt/cdrom/ SourceCode/Linux/tools/busybox-1.1.0.tar.bz2 /root/Myjob #tar –jxvf busybox-1.1.0.tar.bz2 4.2. 编译 busybox 将源码解压之后,进入到 busybox-1.0.0 目录中,运行 make menuconfig 可以打开它的编译界 面。 #cd busybox-1.1.0 #make menuconfig 这个界面和 Linux 内核编译有些接近,如图 1 所示。在这,可以选择编译到 BusyBox 的“内 部命令”。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 110 页 共 175 页 双实科技 图1 在这个菜单界面中除了可以对最终编译到可执行文件中的命令进行选择外,还有很多其他 设置也是非常重要的。下面两个目录是很多人都会感兴趣的: Build Options ---> Installation Options ---> 在 Build Options 里面有是否使用交叉编译的选项(Do you want to build BusyBox with a Cross Compiler),是否静态编译(Build BusyBox as a static binary)如果要对其他平台进行编 译就要选择它并设置相应的编译程序前缀。如图 2 所示。 图2 在 Installation Options 里面可以设置安装的路径,即设置为新文件系统的根目录。当然也可 以用缺省的 _install 目录,安装之后再复制到新文件系统中去。这里我们设置为我们刚才新建 的目录/root/Myrootfs。如图 3 所示。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 111 页 共 175 页 双实科技 图3 设置完毕后保存、退出,执行 make; make install 命令。如图 4 所示。 #make #make install 图4 4.3. 增加的必要的文件 busybox 将在未来的根文件系统中建立/usr、/bin、/sbin 等目录。从中可以看到,编译好的 busybox 可执行文件和其他应用命令的符号链接。典型的 busybox 文件大小在动态链接的情况 下是 300 KB 左右,静态链接为 800 KB 左右,用它实现的文件系统完全可以控制在 1 MB 以下。 但就目前为止,得到的还不是一个完整可用的文件系统,必须要在这个基础上添加一些必要的 文件,让它可以工作。 # cd /root/Myjob/Myrootfs 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 112 页 共 175 页 双实科技 #ls #ls bin #ls usr #mkdir proc root tmp 这里,对于一个最小的文件系统,我们还有三个必要的目录没有。分别是/etc、/lib、/dev。 对于 lib 来说,由于交叉开发工具的库文件很多,而且很大,所以我们在这没有从系统中拷贝 文件,而是从 rootfs.tar.bz2 中拷贝库文件出来。 对于 dev,我们从上面知道,Linux 是通过设备文件来管理设备的。而当我们为一个新的 设备编写完一个驱动程序,并且假设该驱动运行正常,我们只能得到一个设备号,在使用这 个设备以前,我们还必需手工为这个设备建立设备文件。设备文件可以通过 mknod 命令来建 立,但一次手工建立这个多设备未免过于繁复,我们在这里把 rootfs.tar.bz2 的设备文件拷贝过 来。 #cd /root/Myjob #cp /mnt/cdrom/SourceCode/Linux/RootFileSystem/rootfs.tar.bz2 /root/Myjob #tar –jxvf rootfs.tar.bz2 #cp –r rootfs/dev /Myrootfs/ #cp –r rootfs/lib /Myrootfs/ 这里没有从 rootfs.tar.bz2 中把 etc 目录也拷贝过来,主要是因为我们不想新的内核和现有 的文件系统有太多的依赖性。这样不仅会对影响新建的文件系统的质量,而且也不利于文件 系统的升级。当然,我们绝对能把这个目录也拷贝过来。 4.4. 建立文件系统的配置目录 如果你选择了把 rootfs.tar.bz2 里的/etc 目录拷贝到你的文件统里面,这一步你就可以不做 了。这里,我们选择自己去完成这个目录。busybox 源代码 example/bootfloopy/etc 目录中的文 件算是一个简单的例子,可以把其中的文件拷贝过来作为基础。 #cp /root/Myjob/busybox-1.1.0/example/bootfloopy/etc /root/Myrootfs #cd /root/Myrootfs/etc/init.d #vi rcS 在 rcS 里面增加下面两行,如图 5 /bin/mount –n –t ramfs ramfs /tmp /bin/mount –n –t ramfs ramfs /root rcS 这个脚本文件是在系统启动自动执行的,因为我们将会把最终弄好的文件系统做成 cramfs 格式烧到 Nand Flash 里面。而 cramfs 格式是一种只读的格式。所示我们把/tmp、/root 挂载成内存盘,以供临时的读写。但要注意的是,内存盘的内容在系统掉电后就会消失!从 图 5 中我们还看到“/bin/mount –a”,这一句。这一句的作用是挂载由/etc/fstab 定义的挂载项 目。我们在 RedHat 里硬盘的挂载就是在个 fstab 定义的。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 113 页 共 175 页 双实科技 图5 4.5. 测试新的文件系统 文件系统的安装随着应用环境的不同差别比较大。在嵌入式环境中,一般只要通过特殊的 打包工具将文件系统打包,并烧录到非易失性存储器中就可以了。例如,对于 cramfs 类型的文件 系统就可以用 mkcramfs 命令生成文件系统的映像。 在前面的实验中,我们尝试了通过 NFS 方式挂载某个目录到目标系统的 linux 里,并以这种 方式面测试在 PC 里交叉编译出来的程序。在这里,我们做一件更有意义的事情。使用 NFS (网络文件系统)方式进行整个根文件系统的挂载。 1. 修改/etc/exports 输入下面命令,修改/etc/exports 文件。 #vi /etc/exports 添加如下内容,把我们的工作目录/root/Myjob 公布出去。如图 6 所示。 /root/MyRootfs 10.0.0.*(rw,no_root_squash) 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 114 页 共 175 页 双实科技 图6 2. 激活 portmap 与 nfs 服务 输入下列命令配置 PC 的 IP 及重启 portmap 和 nfs 服务 #ifconfig eth0 10.0.0.8 #service portmap restart #service nfs restart 3. 进行连接 连接 PC 和实验箱的串口线、网线、电源线,在 PC 的终端输入下列命令启动 minicom #minicom 按下 PC 的空格键,然后打开实验箱的电源,在 minicom 中,我们将会看到实验箱进入 vivi 的命令行方式。如图 7。在 minicom 中输入下列 vivi 命令,改变 Linux 的启动参数,并启 动 Linux。 vivi>param set linux_cmd_line “noinitrd root=dev/nfs nfsroot=10.0.0.8:/root/Myjob/Myrootfs ip=10.0.0.1:10.0.0.8:10.0.0.8:255.0.0.0:arm:eth0:off init=/linuxrc console=ttyS0” vivi>boot 图7 在 boot Linux 以前,我们也可以输入 param save 命令保存这个 Linux 参数。接着,我们 将看到 Linux 成功的通过 NFS 把我们刚才建立的根文件系统挂载上,如图 8 所示。这里我们 要留意的就是输出信息的后面几句: Look up port of RPC 100003/2 on 10.0.0.8 Look up port of RPC 100005/1 on 10.0.0.8 VFS: Mounted root (nfs filesystem) 从上面的代码,我们可以证实两点。一就是 NFS 其实也是建立在 RPC 的基础上面的。它 也要使用 RPC 服务。第二点就是 Linux 成功的通过 NFS 把我们刚才建立的根文件系统挂载上。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 115 页 共 175 页 双实科技 图8 4.6. 再次裁减库文件 在成功的完成一个完整的根文件系统后,我们必需回头面对一个问题。我们在第三步的 时候把现有的一个文件系统的库文件拷贝到我们新的文件系统。首先要弄清楚的是这些库文 件的最初来源。我们在写程序时一般都会使用 C 语言编译器为我们提供的函数,但这些函数 并不是 C 语言的标准,它们原型都在 C 编译器的一些库文件里面。因此文件系统里的库文件, 它们的最初来源就是编译这个文件系统所用的交叉编译器的库。 第二个要弄清楚的是我们究竟需要哪些库文件,对于很多的人来说,这是一个很头疼的 问题,因为就算程序是我们自己写出来的,我们也不需要指定库文件,我们只需要指定头文 件就行了。那我们的程序究竟用了哪些库文件了呢?在 Linux 里给我们提供了 ldd 这个脚本, 这个脚本在我们的 RedHat 的/bin 里面,只要对它进行一定的改写就能在我们的目标系统里使 用。一个改写好的版本已经在 rootfs.tar.bz2 的/bin 里面了。通过这个脚本我们可以查看一个程 序使用到的哪些库文件,哪些已经有了,哪些还找不到。这样我们就可以有针对性的对库文 件进行裁减了。 下面我们来对刚才的根本件系统的库进行裁减,我们现在实际上只有一个程序,就是 busybox。在另外一个终端窗口中输入下列命令把 ldd 拷贝到我们的文件系统里。 #cd /root/Myjob #cp rootfs/bin/ldd Myrootfs/bin 回到 minicom 的窗口,输入下列命令。如图 9 所示。 #cd /bin #ldd busybox 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 116 页 共 175 页 双实科技 图9 从上图可以看出,busybox 只使用了 libc.so.6 和 ld_linux.so.2。要注意的是这两个可能只 是一个符号文件,这样的话,这些符号文件所指向的文件也是我们要保留的。好了,我们现 在可以把这些文件以外的库文件都删掉。这里,我们在 X Windows 环境里删,最后留下的文 如图 10 所示。 图 10 经过上面的裁减,我们的文件系统没有压缩前的大小从 7.4M 减少到 1.7M。那我们为什 么还要这么大的文件系统呢?因为我们现在只保留了 BusyBox 使用的库文件,很有可能,你 再拷贝一个程序进来就会缺少库文件了。而且,你如果保证不会运行其它的第三方程序,只 使用现在这个目标 linux 系统的内部功能。你大可以在第 2 步时把 BusyBox 编译成静态的,这 样的话就不用再使用任何库文件了。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 117 页 共 175 页 双实科技 3.4 制作和烧写 Cramfs 文件系统 1、 实验目的 z 了解 FLASH 常用的几种文件系统 z 学习制作 cramfs 文件系统 2、 实验设备 z 硬件:PC 机 z 软件:Red Hat9 3、 实验原理 3.1. NOR 和 NAND FLASH 两者是目前市场上主要的非易失性闪存技术,NOR 比较适合存储程序代码,容量通常 小于 16MB;NAND 则更加适合高密度数据存储,其容量可以达到 1GB,所以通常我们采 用 NAND 来存储嵌入式 Linux 系统。 NAND 闪存的存储单元为页和块。一般来说,128MB 以下容量芯片的一页大小为 528 字节, 依次分为 2 个 256 字节的主数据区,最后是 16 字节的备用空间;一个块由若干页组成,通 常为 32 页;一个存储设备又由若干块组成。与其他存储器相比,NAND 闪存具有以下特点: z 不是完全可靠的,每块芯片出厂时都有一定比例的坏块存在。 z 各个存储单元是不可直接改写的,在每次改写操作之前需要先擦除。 z 擦除操作以块为单位进行,而读写操作通常以页为单位进行。 z 各块的擦除次数有限,一般为 10 万~100 万次。 z 使用复杂的 I/O 口串行存取数据。 3.2. cramfs 文件系统 在嵌入式的环境之下,内存和外存资源都需要节约使用。如果使用 RAMDISK 方式来 使用文件系统,那么在系统运行之后,首先要把外存(Flash)上的映像文件解压缩到内存中, 构造起 RAMDISK 环境,才可以开始运行程序。但是它也有很致命的弱点。在正常情况下, 同样的代码不仅在外存中占据了空间(以压缩后的形式存在),而且还在内存中占用了更大的 空间(以解压缩之后的形式存在),这违背了嵌入式环境下尽量节省资源的要求。 使用 cramfs 就是一种解决这个问题的方式。cramfs 是一个压缩式的文件系统,它并不 需要一次性地将文件系统中的所有内容都解压缩到内存之中,而只是在系统需要访问某个位 置的数据的时侯,马上计算出该数据在 cramfs 中的位置,将其实时地解压缩到内存之中, 然后通过对内存的访问来获取文件系统中需要读取的数据。cramfs 中的解压缩以及解压缩之 后的内存中数据存放位置都是由 cramfs 文件系统本身进行维护的,用户并不需要了解具体 的实现过程,因此这种方式增强了透明度,对开发人员来说,既方便,又节省了存储空间。 cramfs 拥有以下一些特性: z 采用实时解压缩方式,但解压缩的时侯有延迟。 cramfs 的数据都是经过处理、打包的,对其进行写操作有一定困难。所以 cramfs 不支持写操作,这个特性刚好适合嵌入式应用中使用 Flash 存储文件系统的场合。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 118 页 共 175 页 双实科技 z z 在 cramfs 中,文件最大不能超过 16MB。 支持组标识(gid),但是 mkcramfs 只将 gid 的低 8 位保存下来,因此只有这 8 位是 有效的。 z 支持硬链接。但是 cramfs 并没有完全处理好,硬链接的文件属性中,链接数仍然 为 1。 特别的,cramfs 的目录中,没有“.”和“..”这两项。因此,cramfs 中的目录的链接数 通常也仅有一个。 编译完成之后,会生成 mkcramfs 和 cramfsck 两个工具,其中 mkcramfs 工具是用来创 建 cramfs 文件系统的,而 cramfsck 工具则用来进行 cramfs 文件系统的释放以及检查。 命令格式如下: mkcramfs [-h] [-e edition] [-i file] [-n name] dirname outfile mkcramfs 的各个参数解释如下: -h:显示帮助信息 -e edition:设置生成的文件系统中的版本号 -i file:将一个文件映像插入这个文件系统之中(只能在 Linux2.4.0 以后的内核版本中使 用) -n name:设定 cramfs 文件系统的名字 dirname:指明需要被压缩的整个目录树 outfile:最终输出的文件 cramfsck 的命令格式: cramfsck [-hv] [-x dir] file cramfsck 的各个参数解释如下: -h:显示帮助信息 -x dir:释放文件到 dir 所指出的目录中 -v:输出信息更加详细 file:希望测试的目标文件 3.3. JFFS 文件系统 JFFS 文件系统是瑞典的 Axis Communications 公司 (www.axis.com) 在 GNU General Public License 下发布的自由软件,主要用于嵌入式 Linux。只需要在自己的嵌入式 Linux 中 加入 JFFS 文件系统并做少量的改动,就可以使用 JFFS 文件系统。通过 JFFS 文件系统,可 以用 Flash 来保存数据,即将 Flash 作为系统的硬盘来使用。可以像操作硬盘上的文件一样 操作 Flash 芯片上的文件和数据。系统运行的参数可以实时保存到 Flash 芯片中,在系统断 电后数据仍然存储在 Flash 芯片中。 JFFS 文件系统是一种“追加式”的文件系统,新的数据总是被追加到上次写入数据的 后面。这种“追加式”的结构就自然实现了“损耗平衡”。 3.4. YAFFS 文件系统 YAFFS(Yet Another Flash File System)类似于 JFFS/JFFS2,是专门为 NAND 闪存设计 的嵌入式文件系统,适用于大容量的存储设备。它是日志结构的文件系统,提供了损耗平衡 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 119 页 共 175 页 双实科技 和掉电保护,可以有效地避免意外掉电对文件系统一致性和完整性的影响。YAFFS 文件系 统是按层次结构设计的,分为文件系统管理层接口、YAFFS 内部实现层和 NAND 接口层, 这样就简化了其与系统的接口设计,可以方便地集成到系统中去。与 JFFS 相比,它减少了 一些功能,因此速度更快,占用内存更少。 YAFFS 充分考虑了 NAND 闪存的特点,根据 NAND 闪存以页面为单位存取的特点,将 文件组织成固定大小的数据段。利用 NAND 闪存提供的每个页面 16 字节的备用空间来存放 ECC(Error Correction Code)和文件系统的组织信息,不仅能够实现错误检测和坏块处理,也 能够提高文件系统的加载速度。YAFFS 采用一种多策略混合的垃圾回收算法,结合了贪心 策略的高效性和随机选择的平均性,达到了兼顾损耗平均和系统开销的目的。 YAFFS 文件系统具有下面的特性: z z z z YAFFS 文件组织结构:按照固定大小的数据段组织文件,每个文件对应专门的文 件头,其中存储所有者 ID、组 ID、长度等信息;文件的数据段按照树型结构进行 组织,以提高查找速度;当有文件需要进行更改的时候,系统将先写入新的文件, 然后再将旧的文件删除;使用页面备用空间中的 ECC 进行错误侦测,进而重试, 多次失败则停用该页面。 YAFFS 物理数据组织:YAFFS 充分利用了 NAND 闪存提供的每个页面 16 字节的 备用空间,其中 6 个字节被用作页面数据的 ECC,2 个字节分别用作块状态字和数 据状态字,其余的 8 字节(64 位)用来存放文件系统的组织信息,即元数据。由于文 件系统的基本组织信息保存在页面的备份空间中,因此,在文件系统加载时只需要 扫描各个页面的备份空间,即可建立起整个文件系统的结构,而不需要像 JFFS 那 样扫描整个介质,从而大大加快了文件系统的加载速度。 YAFFS 擦除块和页面分配:YAFFS 中用数据结构来描述每个擦除块的状态。该数 据结构记录了块状态,并用一个 32 位的位图表示块内各个页面的使用情况。在 YAFFS 中,有且仅有一个块处于“当前分配”状态。新页面从当前进行分配的块 中顺序进行分配,若当前块已满,则顺序寻找下一个空闲块。 YAFFS 垃圾收集机制:将贪心策略和随机选择策略按照一定的比例进行混合使用, 当满足特定的小概率条件时,垃圾回收器会试图随机选择一个可回收的页面;而在 其他情况下,则使用贪心策略回收最“脏”的块。。 4、 实验步骤 4.1. 拷贝文件系统到工作目录中 这里,我们用光盘提供的小文件系统 rootfs.tar.bz2 为例前行说明,当然,如果你已经把 你自己的文件系统弄出来了,你就可以用你的文件系统来进行实验。rootfs.tar.bz2 文件在光 盘的/SourceCode/Linux/RootFileSystem/目录中。输入下面命令拷贝并解压缩。 #mount /mnt/cdrom #mkdir /root/Myjob (如果存在可以省略这一步) #cd /root/Myjob #cp /mnt/cdrom/SourceCode/Linux/RootFileSystem/rootfs.tar.bz2 /root/Myjob #tar –jxvf rootfs.tar.bz2 4.2. 制作 cramfs 文件系统镜像 下面我们使用工具 mkcramfs 来把一个根文件系统做成 cramfs 文件系统镜像。如图 1 所 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 120 页 共 175 页 双实科技 示。 #cp /mnt/cdrom/SourceCode/Linux/tools/mkcramfs #./mkcramfs rootfs rootfs.cramfs /root/Myjob 图1 4.3. 测试 cramfs 文件系统镜像 完成了 cramfs 文件系统镜像的制作,下一步就是把这一镜像直接到 PC 的一个目录下进 行测试。 #mkdir TestCramfs #mount –o loop –t cramfs rootfs.cramfs TestCramfs #ls rootfs #ls TestCramfs 从图 2 可以看出来,挂载后的 cramfs 文件系统镜像的内容和原来的目录是一样的。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 121 页 共 175 页 双实科技 图2 4.4. 烧写 cramfs 文件系统镜像 在上面的实验中,我们在 Redhat 中通 JTAG 接口把 Bootloader 和内核烧写到 FLASH 中, 这种方式的最大缺点就是速度慢,对于文件系统这种庞然大物,更是另人受不了。在这我们 使用别外一种更为快捷的方式,在 Windows 中使用 DNW 通过 USB 烧写 FLASH。在这存在 的另外一个问题就是怎么把 Redhat 中的文件弄到 Windows 中去。这是我不展开说明,要详 细了解的话请自己到因特网上学习,一般的方法有:通过 FTP 传输、通过网上邻居传输、 通过挂载 Windows 下面的分区来传输。这里我选择后都,如果你是在 Windows 中使用 linux 虚拟机来做实验的,推荐使用前者。 1:连接硬件 打开 SinoSys-M3 包装,取出电源线将 SinoSys-M3 与电源相连。取出 USB 线将 SinoSys-M3 和 PC 机 USB 口相连,取出串口线将 SinoSys-M3 和 PC 机的串口相连。 2:安装驱动程序 将光盘里目录 DNW 驱动程序的内容拷贝到用户 PC 机上,然后去除拷贝好的全部文件 的只读属性。记住这点很重要,否则 DNW 不能正常工作。 将 SinoSys-M3 设置为从 Nor-Flash 启动,打开 M3 电源开关。 如果是第一次使用 DNW 工具的话,将会发现 PC 机会有一个 USB 设备被发现,下面 开始添加驱动。选择从列表安装,点击下一步。如下图。 图 3 安装硬件向导 1 选择搜索路径,找到 DNW 驱动程序所在路径(在光盘的/Tools/DNW/里) 。如下图。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 122 页 共 175 页 双实科技 图 4 安装硬件向导 2 点击下一步,找到匹配的驱动程序,如下图。 图 5 安装硬件向导 3 点击下一步,出现如下图对话框,选择“仍然继续”。 图 6 安装硬件向导 4 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 123 页 共 175 页 双实科技 出现如下对话框,说明 DNW 的驱动已经安装成功,接下来就可以使用 DNW 工具了。 图 7 安装硬加向导 5 3:DNW 工具的使用 在 DNW 工具文件夹中打开 DNW 应用程序,界面如下图。 图 8 DNW 工具界面 连接串口,选择“Serial Port”菜单下的“Connect” 。现在就可以看到在图 8 所示的界 面中对话框的标题栏中 COM 串口和 USB 口都已经连接好。选择“Configuration”菜单下的 “Options”,弹出如下对话框。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 124 页 共 175 页 双实科技 图 9 DNW 设置对话框 在这个对话框里我们可以设定 COM 端口,串口比特率和 USB 的下载地址。我们可以 按照图 9 所示进行设置。单击 OK 按钮退出。 程序默认的情况是通过 USB 口下载程序到内存运行的。我门按一下空格键,进入高级 菜单。如图 10 所示。 图 10 高级菜单的各项的含义如下: 1. 2. 3. 4. 5. 6. 7. 8. [1]下载程序到内存并运行。下载的地址就是图 9 的 Download Address。 [2]下载程序到内存但不运行。 [3]运行程序 [4]下载镜像到 NAND FLASH 的某一地方 [5]下载 BootLoader 镜像 [6]下载内核镜像 [7]下载根文件系统镜像 [8]改变串口 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 125 页 共 175 页 双实科技 9. [9]清除没有使用的内存区域 在这里我们输入 7,选择下载根文件系统镜像到 NAND FLASH,这是出现图 11。等待下 载。 图 11 选择“USB Port”菜单下的“Transmit”,弹出打开文件按钮对话框,在对话框里选择要 下载的根文件系统镜像,这是假设根文件系统镜像 rootfs.cramfs 已经拷贝到 G 盘的 Myroofs 里。点击打开按钮就可以把所选择的根文件系统镜像下载 NAND FLASH 中去了。如图 12、 图 13 所示。 图 12 传输文件 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 126 页 共 175 页 双实科技 图 13 文件烧写中 4:测试新文件系统 好了,现在文件系统已经成功的烧写到 Linux 里面了,现在关闭实验箱的电源,把模式 选择开关打到 NAND 一边。这时,从 DNW 的窗口中将看到 Linux 的启动信息。如图 14 所 示。 图 14 从上图我们可以看到内核已经把我们的新的文件系统挂载上了。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 127 页 共 175 页 双实科技 第四篇 Linux 应用编程实验 4.1 多线程应用程序设计 1、 实验目的 z 了解多线程程序设计的基本原理 z 学习 pthread 库函数的使用 2、 实验内容 z 读懂 pthread.c 的源代码。 z 熟悉几个重要的 Pthread 库函数的使用。 z 掌握共享锁和信号量的使用方法。 z 在目标板上运行程序进行实验。 3、 预备知识 z C 语言基础 z 掌握在 Linux 下常用的编辑器的使用 z 掌握 Makefile 的编写和使用 z 掌握 Linux 下程序编译与交叉编译过程 4、 实验设备 z 硬件:PC 机 z 软件:Red Hat9 5、 实验原理 5.1. 多线程的简介 线程(thread)技术早在 60 年代就被提出,但真正应用多线程到操作系统中去,是在 80 年代中期,solaris 是这方面的佼佼者。传统的 Unix 也支持线程的概念,但是在一个进程 (process)中只允许有一个线程,这样多线程就意味着多进程。现在,多线程技术已经被许 多操作系统所支持,包括 Windows/NT,当然,也包括 Linux。 为什么有了进程的概念后,还要再引入线程呢?使用多线程到底有哪些好处?什么的系 统应该选用多线程?我们首先必须回答这些问题。 使用多线程的理由之一是和进程相比,它是一种非常"节俭"的多任务操作方式。我们知 道,在 Linux 系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表 来维护它的代码段、堆栈段和数据段,这是一种"昂贵"的多任务工作方式。而运行于一个进 程中的多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花 费的空间远远小于启动一个进程所花费的空间,而且,线程间彼此切换所需的时间也远远小 于进程间切换所需要的时间。据统计,总的说来,一个进程的开销大约是一个线程开销的 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 128 页 共 175 页 双实科技 30 倍左右,当然,在具体的系统上,这个数据可能会有较大的区别。 使用多线程的理由之二是线程间方便的通信机制。对不同进程来说,它们具有独立的数 据空间,要进行数据的传递只能通过通信的方式进行,这种方式不仅费时,而且很不方便。 线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其 它线程所用,这不仅快捷,而且方便。当然,数据的共享也带来其他一些问题,有的变量不 能同时被两个线程所修改,有的子程序中声明为 static 的数据更有可能给多线程程序带来灾 难性的打击,这些正是编写多线程程序时最需要注意的地方。 除了以上所说的优点外,不和进程比较,多线程程序作为一种多任务、并发的工作方式, 当然有以下的优点: 1) 提高应用程序响应。这对图形界面的程序尤其有意义,当一个操作耗时很长时,整 个系统都会等待这个操作,此时程序不会响应键盘、鼠标、菜单的操作,而使用多线程技术, 将耗时长的操作(time consuming)置于一个新的线程,可以避免这种尴尬的情况。 2) 使多 CPU 系统更加有效。操作系统会保证当线程数不大于 CPU 数目时,不同的线 程运行于不同的 CPU 上。 3) 改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半 独立的运行部分,这样的程序会利于理解和修改。 Linux 系统下的多线程遵循 POSIX 线程接口,称为 pthread。编写 Linux 下的多线程程 序,需要使用头文件 pthread.h,连接时需要使用库 libpthread.a。顺便说一下,Linux 下 pthread 的实现是通过系统调用 clone()来实现的。clone()是 Linux 所特有的系统调用,它的使 用方式类似 fork,关于 clone()的详细情况,有兴趣的读者可以去查看有关文档说明。 5.2. 多线程 API 的主要函数说明 1) 线程创建函数 函数原型: #include int pthread_create(pthread_t *restrict tidp,const pthread_attr_t *restrict attr, void *(*start_rtn) (void),void *restrict arg); 第一个参数为指向线程标识符的指针,第二个参数用来设置线程属性,第三个参数是 线程运行函数的起始地址,最后一个参数是运行函数的参数。这里,我们的函数 thread 不 需要参数,所以最后一个参数设为空指针。第二个参数我们也设为空指针,这样将生成默认 属性的线程。当创建线程成功时,函数返回 0,若不为 0 则说明创建线程失败,常见的错误 返回代码为 EAGAIN 和 EINVAL。前者表示系统限制创建新的线程,例如线程数目过多了;后 者表示第二个参数代表的线程属性值非法。创建线程成功后,新创建的线程则运行参数三和 参数四确定的函数,原来的线程则继续运行下一行代码。 2) 等待指定线程的结束 函数 pthread_join 用来等待一个线程的结束。函数原型为: extern int pthread_join __P ((pthread_t __th, void **__thread_return)); 第一个参数为被等待的线程标识符,第二个参数为一个用户定义的指针,它可以用来存 储被等待线程的返回值。这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等 待的线程结束为止,当函数返回时,被等待线程的资源被收回。 3) 线程退出 extern void pthread_exit((void *__retval)) 一个线程的结束有两种途径,一种是象我们上面的例子一样,函数结束了,调用它的线 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 129 页 共 175 页 双实科技 程也就结束了;另一种方式是通过函数 pthread_exit 来实现。它的函数原型为: 唯一的参数是函数的返回代码,只要 pthread_join 中的第二个参数 thread_return 不是 NULL,这个值将被传递给 thread_return。最后要说明的是,一个线程不能被多个线程等待, 否则第一个接收到信号的线程成功返回,其余调用 pthread_join 的线程则返回错误代码 ESRCH。 5.3. 条件变量 用互斥锁来实现线程间数据的共享和通信,互斥锁一个明显的缺点是它只有两种状态: 锁定和非锁定。而条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥 锁的不足,它常和互斥锁一起使用。使用时,条件变量被用来阻塞一个线程,当条件不满足 时,线程往往解开相应的互斥锁并等待条件发生变化。一旦其它的某个线程改变了条件变量, 它将通知相应的条件变量唤醒一个或多个正被此条件变量阻塞的线程。这些线程将重新锁定 互斥锁并重新测试条件是否满足。一般说来,条件变量被用来进行线承间的同步。 1) pthread_cond_init 函数 条件变量的结构为 pthread_cond_t,函数 pthread_cond_init()被用来初始化一个条件变 量。它的原型为: extern int pthread_cond_init __P ((pthread_cond_t *__cond,__const pthread_condattr_t *__cond_attr)); 其 中 cond 是 一 个 指 向 结 构 pthread_cond_t 的 指 针 , cond_attr 是 一 个 指 向 结 构 pthread_condattr_t 的指针。结构 pthread_condattr_t 是条件变量的属性结构,和互斥锁一样我 们 可 以 用 它 来 设 置 条 件 变 量 是 进 程 内 可 用 还 是 进 程 间 可 用 , 默 认 值 是 PTHREAD_ PROCESS_PRIVATE,即此条件变量被同一进程内的各个线程使用。注意初始化条件变量只 有未被使用时才能重新初始化或被释放。释放一个条件变量的函数为 pthread_cond_ destroy (pthread_cond_t cond)。 2) pthread_cond_wait 函数 函数 pthread_cond_wait()使线程阻塞在一个条件变量上。它的函数原型为: extern int pthread_cond_wait __P ((pthread_cond_t *__cond, pthread_mutex_t *__mutex)); 线程解开 mutex 指向的锁并被条件变量 cond 阻塞。线程可以被函数 pthread_cond_signal 和函数 pthread_cond_broadcast 唤醒,但是要注意的是,条件变量只是起阻塞和唤醒线程的 作用,具体的判断条件还需用户给出,例如一个变量是否为 0 等等,这一点我们从后面的例 子中可以看到。线程被唤醒后,它将重新检查判断条件是否满足,如果还不满足,一般说来 线程应该仍阻塞在这里,被等待被下一次唤醒。这个过程一般用 while 语句实现。 3) pthread_cond_timedwait 函数 另一个用来阻塞线程的函数是 pthread_cond_timedwait() ,它的原型为: extern int pthread_cond_timedwait __P ((pthread_cond_t *__cond, pthread_mutex_t *__mutex, __const struct timespec *__abstime)); 它比函数 pthread_cond_wait()多了一个时间参数,经历 abstime 段时间后,即使条件 变量不满足,阻塞也被解除。 4) pthread_cond_signal 函数 函数 pthread_cond_signal()的原型为: extern int pthread_cond_signal __P ((pthread_cond_t *__cond)); 它用来释放被阻塞在条件变量 cond 上的一个线程。多个线程阻塞在此条件变量上时, 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 130 页 共 175 页 双实科技 哪一个线程被唤醒是由线程的调度策略所决定的。要注意的是,必须用保护条件变量的互斥 锁来保护这个函数,否则条件满足信号又可能在测试条件和调用 pthread_cond_wait 函数之 间被发出,从而造成无限制的等待。 6、 实验步骤 此实验为著名的生产者—消费者问题模型的实现,主程序中分别启动生产者线程和消费 者线程。生产者线程不断顺序地将 0~1000 的数字写入共享的循环缓冲区,同时消费者线程 不断地从共享的循环缓冲区读取数据。 1) 进入 exp/basic/pthread 目录,使用 vi 编辑器或其他编辑器阅读理解源代码。 2) 运行 make 产生 pthread 可执行文件。 3) 切换到 MiniCOM 终端窗口,使用 NFS mount 开发主机的/arm2440 到/host 目录。 4) 运行 pthreadٛ ,观察运行结果的正确性。 5) 修改一些参数,再次运行调试,加深对多线程的理解。 6) 源代码的流程图: 进行生产(put) 进行消费(get) 获得互斥锁 获得互斥锁 写指针+1是否等于读指针 写指针是否等于读指针 是 是 等待条件变量notfull 等待条件变量notempty 否 否 写入数据 读取数据 设置条件变量notemptty 设置条件变量notfull 释放互斥锁 释放互斥锁 生产、消费流程图 7) 参考源代码: #include#include 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 131 页 共 175 页 双实科技 #define BUFFER_SIZE 8 struct prodcons { int buffer[BUFFER_SIZE]; pthread_mutex_t lock; //互斥 LOCK int readpos , writepos; pthread_cond_t notempty; //缓冲区非空条件判断 pthread_cond_t notfull; //缓冲区未满条件判断 }; void init(struct prodcons * b){ pthread_mutex_init(&b->lock,NULL); pthread_cond_init(&b->notempty,NULL); pthread_cond_init(&b->notfull,NULL); b->readpos=0; b->writepos=0; } void put(struct prodcons* b,int data){ pthread-_mutex_lock(&b->lock); if((b->writepos + 1) % BUFFER_SIZE == b->readpos) { pthread_cond_wait(&b->notfull, &b->lock) ; } b->buffer[b->writepos]=data; b->writepos++; if(b->writepos >= BUFFER_SIZE) b->writepos=0; pthread_cond_signal(&b->notempty); pthread_mutex_unlock(&b->lock); } int get(struct prodcons *b){ int data; pthread_mutex_lock(&b->lock); if(b->writepos == b->readpos) { pthread_cond _wait(&b->notempty, &b->lock); 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 132 页 共 175 页 双实科技 } data = b->buffer[b->readpos]; b->readpos++; if(b->readpos >= BUFFER_SIZE) b->readpos=0; pthread_cond_signal(&b->notfull); pthread_mutex_unlock(&b->lock); return data; } #define OVER (-1) struct prodcons buffer; void *producer(void *data) { int n; for(n = 0; n < 10000; n++) { printf("%d \n", n) ; put(&buffer, n); } put(&buffer, OVER); return NULL; } void *consumer(void * data) { int d; while(1) { d = get(&buffer); if(d == OVER) break; printf("%d\n", d); 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 133 页 共 175 页 双实科技 } return NULL; } int main(void) { pthread_t th_a, th_b; void *retval; init(&buffer); pthread_create(&th_a, NULL, producer, 0); pthread_create(&th_b, NULL, consumer, 0); pthread_join(th_a, &retval); pthread_join(th_b, &retval); return 0; } 7、 思考题 1) 2) 加入一个新的线程用于处理键盘的输入,并在按键为 ESC 时终止所有线程/ 线程优先级的控制。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 134 页 共 175 页 双实科技 4.2 串口端口应用程序设计 1、 实验目的 z 了解 Linux 环境下串行程序设计的基本方法。 z 掌握终端的主要属性及设置方法,掌握终端 IO 函数的使用。 z 学习使用多线程来完成串口的收发处理。 2、 实验内容 z 读懂程序源代码。 z 学习终端 IO 函数 tcgetattr()、tcsetattr()和 tcflush()的使用方法 z 学习将多线程编程应用到串口的接收和发送程序设计中。 3、 预备知识 z C 语言基础 z 掌握在 Linux 下常用的编辑器的使用 z 掌握 Makefile 的编写和使用 z 掌握 Linux 下程序编译与交叉编译过程 4、 实验设备 z 硬件:PC 机 z 软件:Red Hat9 5、 实验原理 Linux 操作系统从一开始就对串行口提供了很好的支持,为进行串行通信提供了大量的 函数,本实验主要介绍在 Linux 中进行串口通信编程的基本方法。 5.1. 串口操作需要的头文件 #include #include #include #include #include#include 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 135 页 共 175 页 双实科技 #include #include 5.2. 打开串口 在 Linux 下 串 口 文 件 是 位 于 /dev 下 的 串 口 一 为 /dev/ttyS0 , 串 口 二 为 /dev/ttyS1 。打开串口是通过使用标准的文件打开函数操作: int fd; fd = open( "/dev/ttyS0", O_RDWR); if (-1 == fd){ perror(" 提示错误!"); } 5.3. 设置串口 基本的设置串口包括波特率设置,效验位和停止位设置。串口的设置主要是设置 struct termios 结构体的各成员值。 struct termio { unsigned short c_iflag; unsigned short c_oflag; unsigned short c_cflag; unsigned short c_lflag; unsigned char c_line; unsigned char c_cc[NCC]; }; 设置这个结构体很复杂,我这里就只说说常见的一些设置: 1) 波特率设置 下面是修改波特率的代码: struct termios Opt; tcgetattr(fd, &Opt); cfsetispeed(&Opt,B19200); cfsetospeed(&Opt,B19200); tcsetattr(fd,TCANOW,&Opt); 2) 效验位和停止位的设置: 无效验 8位 Option.c_cflag &= ~PARENB; Option.c_cflag &= ~CSTOPB; Option.c_cflag &= ~CSIZE; Option.c_cflag |= ~CS8; 奇效验(Odd) 7位 Option.c_cflag |= ~PARENB; Option.c_cflag &= ~PARODD; 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 136 页 共 175 页 双实科技 Option.c_cflag &= ~CSTOPB; Option.c_cflag &= ~CSIZE; Option.c_cflag |= ~CS7; 偶效验(Even) Space 效验 7位 Option.c_cflag &= ~PARENB; Option.c_cflag |= ~PARODD; Option.c_cflag &= ~CSTOPB; Option.c_cflag &= ~CSIZE; Option.c_cflag |= ~CS7; 7位 Option.c_cflag &= ~PARENB; Option.c_cflag &= ~CSTOPB; Option.c_cflag &= &~CSIZE; Option.c_cflag |= CS8; 3) 设置停止位 1 位: Option.c_cflag &= ~CSTOPB; 2 位: Option.c_cflag |= CSTOPB; 需要注意的是: 如果不是开发终端之类的,只是串口传输数据,而不需要串口来处理, 那么使用原始模式(Raw Mode)方式来通讯,设置方式如下: options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); options.c_oflag &= ~OPOST; 5.4. 读写串口 设置好串口之后,读写串口就很容易了,把串口当作文件读写就是。 1) 发送数据 char buffer[1024]; int Length; int nByte; nByte = write(fd, buffer ,Length) 2) 读取串口数据 使用文件操作 read 函数读取,如果设置为原始模式(Raw Mode)传输数据,那么 read 函数返回的字符数是实际串口收到的字符数。可以使用操作文件的函数来实现异步读取,如 fcntl,或者 select 等来操作。 char buff[1024]; int Len; int readByte = read(fd,buff,Len); 5.5. 关闭串口 关闭串口就是关闭文件。 close(fd); 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 137 页 共 175 页 双实科技 6、 实验步骤 1) 2) 3) 4) 5) 6) 进入 exp/basic/tty 目录,使用 vi 编辑器或其他编辑器阅读理解源代码。 运行 make 产生 term 可执行文件。 切换到 MiniCOM 终端窗口,使用 NFS mount 开发主机的/arm2440 到/host 目录。 运行 termٛ ,观察运行结果的正确性。 修改一些参数,再次运行调试,加深对串口编程的理解。 源代码的流程图: 程序流程图 7) 参考源代码: #include #include#include#include#include#include #define BAUDRATE B115200 #define COM1 "/dev/ttyS0" #define COM2 "/dev/ttyS1" #define ENDMINITERM 27 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 138 页 共 175 页 双实科技 #define FALSE 0 #define TRUE 1 volatile int STOP=FALSE; volatile int fd; void child_handler(int s) { printf("stop!!!\n"); STOP=TRUE; } void* keyboard(void * data) { int c; for (;;){ c=getchar(); if( c== ENDMINITERM){ STOP=TRUE; break ; } } return NULL; } void* receive(void * data) { int c; printf("read modem\n"); while (STOP==FALSE) { read(fd,&c,1); write(1,&c,1); } printf("exit from reading modem\n"); return NULL; } void* send(void * data) { int c='0'; 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 139 页 共 175 页 双实科技 printf("send data\n"); while (STOP==FALSE) { c++; c %= 255; write(fd,&c,1); usleep(100000); } return NULL; } int main(int argc,char** argv) { struct termios oldtio,newtio,oldstdtio,newstdtio; struct sigaction sa; int ok; pthread_t th_a, th_b, th_c; void * retval; if( argc > 1) fd = open(COM2, O_RDWR | O_APPEND); else fd = open(COM1, O_RDWR ); //| O_NOCTTY |O_NONBLOCK); if (fd <0) { perror(COM1); exit(-1); } printf("The port is %d", fd); tcgetattr(0,&oldstdtio); tcgetattr(fd,&oldtio); tcgetattr(fd,&newstdtio); newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD; newtio.c_iflag = IGNPAR; newtio.c_oflag = 0; newtio.c_lflag = 0; newtio.c_cc[VMIN]=1; newtio.c_cc[VTIME]=0; tcflush(fd, TCIFLUSH); tcsetattr(fd,TCSANOW,&newtio); 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 140 页 共 175 页 双实科技 //pthread_mutex_init(&lock, NULL); sa.sa_handler = child_handler; sa.sa_flags = 0; sigaction(SIGCHLD,&sa,NULL); pthread_create(&th_a, NULL, keyboard, 0); pthread_create(&th_c, NULL, send, 0); //pthread_create(&th_b, NULL, receive, 0); pthread_join(th_a, &retval); //pthread_join(th_b, &retval); pthread_join(th_c, &retval); tcsetattr(fd,TCSANOW,&oldtio); tcsetattr(0,TCSANOW,&oldstdtio); close(fd); exit(0); 7、 思考题 1) 2) 编写个简单的文件收发程序完成串口文件下载 终端对特殊字符的处理 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 141 页 共 175 页 双实科技 4.4 GPRS 通信实验 1、 实验目的 z 掌握 GPRS 通信原理 z 了解 GSM/GPRS 原理 z 掌握基本的 AT 命令 z 学习使用 ARM 嵌入式开发平台对 GPRS 进行控制 2、 实验内容 z 学习 GPRS 的 AT 命令。 z 通过对串口编程来控制 GPRS 模块,实现发送短信。 3、 预备知识 z C 语言基础 z 掌握在 Linux 下常用的编辑器的使用 z 掌握 Makefile 的编写和使用 z 掌握 Linux 下程序编译与交叉编译过程 4、 实验设备 z 硬件:PC 机 z 软件:Red Hat9 5、 实验原理 5.1. GSM 的历史发展 从 20世 纪 20年 代 开 始 移 动 通 信 技 术 得 到 了 发 展 , 20世 纪 40年 代 进 入 了 建 设 公 用 移动通信系 统的阶段。 随着移动通 信的无线传 输、信道管 理及移动交 换等技术 的 发 展成熟,无 绳电话、无 线寻呼、陆 地蜂窝移动 通信、卫星 移动通信等 移动通信 系 统 相继发展起来。 自 20世 纪 80年 代 中 期 以 来 , 蜂 窝 移 动 通 信 从 第 一 代 的 模 拟 蜂 窝 移 动 通 信 系 统 发 展 成 第 二 代 的 数 字 蜂 窝 移 动 通 信 系 统 。 作 为 欧 洲 一 个 数 字 蜂 窝 移 动 通 信 标 准 的 GSM 系统于1991年正式在欧 洲面世,由 于其公开的 规范标准和 诸多优点, 很快就在 全 世 界范围内的 到了广泛的 应用,实现 了世界范围 内移动用户 的联网漫游 。截止2001年 一季度我国移动用户总数已达到1亿户。 5.2. GSM 的基本特点 可以与各种公用通信网互连互通,尤其与ISDN的兼容性,可提供更多的业务,各种接口 规范明确,网络适合未来数字化发展的要求。 GSM组网结构灵活方便,能更有效地使用无线频率,抗干扰性强,通信质量高,能提供相当 好的话音质量。 采用了鉴权、语音加密等技术使用户信息安全性得到保证。在采用GSM系统所有国家范 围内,可提供穿越国界的自动漫游功能。用户终端更小、更轻便、功能更强。 5.3. GSM 的系统功能 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 142 页 共 175 页 双实科技 GSM是一种提供话音、数据、补充业务等多种服务的系统。 话音业务是GSM系统提供的基本业务,允许用户在世界范围内任何地点能同固定电话用 户、移动电话用户以及专用网用户进行双向通话联系。从电话中派生出的另一项业务是语音 信箱,声音信息被存储,以备收方提取,在呼叫不能接通时,用户可将声音信息存入GSM的 语音信箱;或者用户直接接入语音信箱。 数据业务提供了固定用户和ISDN用户所能享用的大部分业务,包括文字、图象、传真、 计算机文件、访问Internet等服务。 补充业务如来电显示、呼叫追踪、短消息业务等。 5.4. GPRS 网络概述 GPRS (General Packet Radio Service)是一种基于包的无线通讯服务。它将使得通讯 速率从56一直上升到114Kbps,并且支持计算机和移动用户的持续连接。较高的数据吞吐能 力使得可以使用手持设备和笔记本电脑进行电视会议和多媒体页面以及类似的应用。GPRS 是基于Global System for Mobile(GSM),并且能完成现有的一些服务,例如:蜂窝电话电 路交换(circuit-switched)连接和短消息服务(SMS)。 在理论上,GPRS包服务的花费将比电路交换服务所花的费用要少。信道是共享使用的, 是需要的时候才有包产生。那么比专用的连接要节省很多资源。它将使得为用户提供应用服 务更加简单。因为以往为了适应终端设备的缓慢速度而增加的缓冲中间件(middleware)已经 没有必要了。一旦GPRS成为现实,移动用户就可以随时访问自己的虚拟专用网络(VPN),而 不是每次都需要拨号上网。 GPRS将完善Bluetooth技术(成为一种标准,代替现有的有线和无线连接技术)。另外对 于Internet协议(IP), GPRS支持X.25(一种基于包的协议,主要在欧洲地区广泛应用) 。GPRS 要逐渐迈向高性能数据GSM环境(Enhanced Data GSM Environment,EDGE)和通用移动电话 服务(Universal Mobile Telephone Service,UMTS)。 5.5. 早期的 AT 命令 最早生产调制解调器的公司是贺氏,后来组建的厂家制造的调制解调器都与HAYS兼容, 大部分的通信软件使用菜单来对调制解调器进行配置、检测。但是有些通信软件要求用户直 接发命令给调制解调器,在这种情况下必须使用AT命令。 AT命令集是调制解调器通信接口的工业标准,AT命令是调制解调器可以识别并执行的命 令。AT命令简单容易掌握,使用它可以配置调制解调器,配合通信软件工作与远端系统通信 发起或应答一个呼叫。 使用AT命令设置调制解调器时,用户使用的通信软件必须提供一个到调制解调器的直接 连接状态,使你能够从命令行输入所需的AT命令。如在WINDOWS95下的“超级终端”中建立 一个直接到串口的连接便可使用AT命令,也可使用ONLAN/PC软件的终端方式。但是不能在操 作系统下(如:DOS下)直接使用AT命令。 AT命令的基本格式为:AT+命令字符及相关设置参数,例如:ATDT0,2043506 这个命令 表示使用音频拨号方式拨外线电话2043506。AT是前导符,D是命令字符表示拨号,T这个参 数表示用音频拨号。先拨“0”,紧随其后的逗号表示延迟处理下一个字符称为拨号修正符。 (可以通过设置S8寄存器的值定义延迟的时间,默认为2秒。范围为0~65秒)。 5.6. GPS/GPRS AT 命令 GPS/GPRS 的AT命令是对早期调制解调器AT命令的一个扩充,在早其AT命令的基础上加 上对GSM/GPRS业务支持的扩展AT命令集,扩展AT命令集基本格式为“AT+”+命令字符及 相关设置参数。下面例举一些GPS/GPRS的AT命令。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 143 页 共 175 页 双实科技 读取波特率 AT+IPR=? 返回: +IPR: (0,19200,38400,57600,115200) 读取短信中心号码 AT+CSCA? 返回: +CSCA: "+8613800571500",145 移动 AT+CSCA? 返回: +CSCA: "002B003800360031003300380030003000 3500370031003500300030",145 联通 AT+CSCA? +CSCA: "002B003800360031003300300031003000 3300360030003500300030",145 读取日期时间 AT+CCLK? 返回:+CCLK: "04/11/01,08:51:55" 读取电话簿容量 AT+CPBR=? 返回:+CPBR: (1-250),20,12 AT+CMGL=? +CMGL: (0-4) 键盘加锁 AT^SLCK="CS",1 键盘解锁 AT^SLCK="CS",0 拨号 ATD75977160 不成功返回NO CARRIER 重播上次号码 ATDL 关机 AT^SMSO 返回:^SMSO: MS OFF 读取通讯类型(查询可使用的功能列表) AT+GCAP 返回:+GCAP: +CGSM 读取设备名称 AT+GMI 返回:SIEMENS AT+FMFR? 返回:SIEMENS AT+CGMI 返回“SIEMENS 读取软件名称 AT+GMM 返回:Gipsy Soft Protocolstack AT+FMDL? 返回:Gipsy Soft Protocolstack 读取软件版本 AT+GMR 返回:V2.550 读取序列号(IMEI): AT+GSN 返回:352030000110312 AT+CGSN 返回:352030000110312 ATD*#06# 返回:352030000110312 读取IMSI号码(国际移动电话支持认证) AT+CIMI 返回:460008883116357 读取SIM卡认证号码(西门子增强指令) AT^SCID 返回:^SCID: 89860088880351226357 读取设备型号 AT+CGMM 返回:M55C 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 144 页 共 175 页 双实科技 4 拨号中 读取版本号 AT+CGMR 返回:08 挂断拨号 AT+CHUP OK 读取锁定代码 AT+CLCK=? 返回: +CLCK: ("CS","PS","PF","SC","AO","OI","OX" ,"AI","IR","AB","AG","AC","FD","PN" ,"P U","PP","PC") 读取声音音量 AT+CLVL? 返回:+CLVL: 4 读取是否静音 AT+CMUT? 返回:+CMUT: 0 读取操作名称 AT+COPN? 返回:+COPN: "736001","NUEVATEL" +COPN: "744001","HOLA PARAGUAY " +COPN: "33211","Blue Sky" +COPN: "34430","APUA-PCS" +COPN: "37001","ORANGE" +COPN: "52015","TH ACT 1900" +COPN: "54411","Blue Sky AS" +COPN: "70610","ESV PERSONAL" +COPN: "71610","TIM PERU" +COPN: "72234","PERSONAL" +COPN: "73001","ENTEL PCS" +COPN: "73010","ENTEL PCS" +COPN: "73602","EMOVIL" +COPN: "73601","NUEVATEL" +COPN: "74401","HOLA PARAGUAY " 读取手机状态 AT+CPAS 返回:+CPAS: 0 0 待机 3 有电话 读取电话簿用户 AT+CPBR=1,1 返回: +CPBR: 1,"13023615986",129,"9A6C76F88D4B" AT+CPBR=1,2 返回: +CPBR: 1,"13023615986",129,"9A6C76F88D4B" +CPBR: 2,"057185977160",129,"534E676D516C5 3F8" 读取电话簿 AT^SPBG=1,10 ^SPBG: 1,"057178977160",129,"534E676D516C5 3F8" ^SPBG: 2,"13588079783",129,"80E15BA3" ^SPBG: 3,"13758127643",129,"9093521A" ^SPBG: 4,"13023615986",129,"9A6C76F88D4B" 读取电话簿登记条目,2为2条通讯录,250 为可以容纳250条记录 AT+CPBS? 返回:+CPBS: "SM",2,250 读取PIN码状态 AT+CPIN? 返回:+CPIN: READY 读取费率设置 AT+CPUC? 返回:+CPUC: "","0" 读取密码设置 AT+CPWD=? 返回: +CPWD: ("PS",8),("PF",8),("SC",8),("AO",4) ,("OI",4),("OX",4),("AI",4),("IR",4 ),( "AB",4),("AG",4),("AC",4),("PN",8), ("PU",8),("PP",8),("PC",8),("P2",8) 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 145 页 共 175 页 双实科技 读取网络注册 AT+CREG? 返回:+CREG: 0,1 读取信号强度 AT+CSQ 返回:+CSQ: 26,99 AT+CSQ=? +CSQ: (0-31,99),(0-7,99) 0 -113 dBm or less 1 -111 dBm 2...30 -109... -53 dBm 31 -51 dBm or greater 99 not known or not detectable 读取短信支持格式0,PDU,1,TEXT AT+CMGF? 返回:+CMGF: 0 从首选设备中读取短信 AT+CMGL=1 +CMGL: 2,1,,28 0891683108501705F0040D9168317747154 9F0000040016251920200098A640F269BC5 DA41 +CMGL: 3,1,,28 0891683108501705F0040D9168317747154 9F0000040016251928300098A640F0683C1 DA41 ok 1) text 模式: “REC UNREAD” 未读信息 (默认) “REC READ” 已读信息 “STO UNSENT” 未发送信息 “STO SENT” 已发送信息 “ALL” 所有信息 2) PDU 模式: 0 未读信息 (默认) 1 已读信息 2 未发送信息 3 已发送信息 4 全部信息 单条读取短信 AT+CMGR=8 返回:+CMGR: 1,,28 0891683108501705F0040D9168317747154 9F0000040017290146500098A640F0683C5 DA41 发送短信 AT+CMGS=1 编辑短信到存储器 AT+CMGW= 从存储器中发短信 AT+CMSS=? 读取手机短信容量状况,"ME"74为手机中 74条 "SM" 为SIM卡 AT+CPMS? 返 回 : +CPMS: "ME",74,100,"SM",0,50,"SM",0,50 联通 AT+CPMS? +CPMS: "ME",74,100,"SM",18,40,"SM",18,40 读取信息服务,0不支持 1支持 AT+CSMS? 返回:+CSMS: 0,1,1,1 情况已拨号码 AT^SDLD OK 列出已拨号码清单 AT^SCNI 返回: ^SCNI: 1 ^SCNI: 2 ^SCNI: 3 ^SCNI: 4 ^SCNI: 5 ^SCNI: 6 ^SCNI: 7 列表支持网络 AT+CSCS=? 返回:+CSCS: ("GSM","UCS2") 读取当前支持网络 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 146 页 共 175 页 双实科技 AT+CSCS? 返回:+CSCS: "UCS2" 查询错误原因 AT+CEER 返回:+CEER: 0,0 当前网络运营商 46001 联通 移动 AT+CPOL? +CPOL: 1,2,"46000" 46000 移动 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 147 页 共 175 页 双实科技 OK AT+CPOL=? +CPOL: (1-14),(2) --------------------联通 AT+CPOL=? +CPOL: (1-10),(2) OK AT+CPOL? +CPOL: 1,2,"46001" 当前网络注册情况 AT+CREG=? +CREG: (0-2) OK AT+CREG? +CREG: 0,1 选择当有新的短信来时系统提示方式 AT+CNMI? +CNMI: 0,0,0,0,1 OK AT+CNMI=? +CNMI: (0,1),(0,1),(0,2),(0,2),(1) 选择系统广播短信的类型 at+cscb? +CSCB: 0,"","" OK at+cscb=? +CSCB: (0,1) 显示当前呼叫认证 AT+CLIP? +CLIP: 0,1 OK AT+CLIP=? +CLIP: (0,1) 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 148 页 共 175 页 双实科技 6、 实验步骤 此实验为用 AT 命令进行短信的接收与发送。GPRS 模块为串口接口,所以通过串口与 GPRS 模块进行通讯。 1) 首先理解了串口通信的原理与这部源代码 2) 理解了 AT 命令,理解了 AT 命令进行短信的发送与接收这部分源代码 3) 理解源码中的主函数部分的代码 4) 编译生成 BIN 文件,下载到开发板。 5) 运行程序,验证结果。 6) 参考源代码: (见光盘) 7、 思考题 1) 在理解源代码的基础上,进行功能的扩展。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 149 页 共 175 页 双实科技 第五篇 Linux 驱动模块实验 5.1 内核驱动设计入门—模块方式驱动 1、 实验目的 z 学习在 Linux 下进行驱动设计的原理 z 掌握使用模块方式进行驱动开发调试的过程。 2、 实验内容 z 学习并实现驱动程序的接口函数。 z 分析并理解驱动与应用程序的交互过程。 3、 预备知识 z C 语言基础 z 掌握在 Linux 下常用的编辑器的使用 z 掌握 Makefile 的编写和使用 z 掌握 Linux 下程序编译与交叉编译过程 z 有驱动开发的基本知识 4、 实验设备 z 硬件:PC 机 z 软件:Red Hat9 5、 实验原理 5.1 概述 Linux 中的驱动设计是嵌入式 Linux 开发中十分重要的部分,它要求开发者不仅要熟悉 Linux 的内核机制、驱动程序与用户级应用程序的接口关系、考虑系统中对设备的并发操作 等等,而且还要非常熟悉所开发硬件的工作原理。这对驱动开发者提出了比较高的要求,这 个实验主要是给大家进入驱动设计提供一个简单入门的一个实例,并不需要提供太多与硬件 相关的内容,这部分应该是通过仔细阅读芯片厂家提供的资料来解决。 驱动程序的作用是应用程序与硬件之间的一个中间软件层,驱动程序应该为应用程序展 现硬件的所有功能,不应该强加其他的约束,对于硬件使用的权限和限制应该由应用程序层 控制。但是有时驱动程序的设计是跟所开发的项目相关的,这时就可能在驱动层加入一些与 应用相关的设计考虑,主要是因为在驱动层的效率比应用层高,同时为了项目的需要可能只 强化或优化硬件的某个功能,而弱化或关闭其他一些功能;到底需要展现硬件的哪些功能全 都由开发者根据需要而定。驱动程序有时会被多个进程同时使用,这时我们要考虑如何处理 并发的问题,就需要调用一些内核的函数使用互斥量和锁等机制。驱动程序主要需要考虑下 面三个方面:提供尽量多的选项给用户,提高驱动程序的速度和效率,尽量使驱动程序简单, 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 150 页 共 175 页 双实科技 使之易于维护。 Linux 的驱动开发调试有两种方法,一种是直接编译到内核,再运行新的内核来测试; 二是编译为模块的形式,单独加载运行调试。第一种方法效率较低,但在某些场合是唯一的 方法。模块方式调试效率很高,它使用 insmod 工具将编译的模块直接插入内核,如果出现 故障,可以使用 rmmod 从内核中卸载模块。不需要重新启动内核,这使驱动调试效率大大 提高。我们的实验在 PC 机和 SinoSys-M3 上都可以运行,编译时使用不同的编译器就可以了。 5.2 驱动程序与应用程序的区别 应用程序一般有一个 main 函数,从头到尾执行一个任务;驱动程序却不同,它没有 main 函数,通过使用宏 module_init(初始化函数名); 将初始化函数加入内核全局初始化函数列表 中,在内核初始化时执行驱动的初始化函数,从而完成驱动的初始化和注册,之后驱动便停 止等待被应用软件调用。驱动程序中有一个宏 moudule_exit(退出处理函数名)注册退出处理函 数。它在驱动退出时被调用。 应用程序可以和 GLIBC 库连接,因此可以包含标准的头文件,比如、, 在驱动程序中是不能使用标准 C 库的,因此不能调用所有的 C 库函数,比如输出打印函数 只能使用内核的 printk 函数,包含的头文件只能是内核的头文件,比如。 5.3 内核版本与编译器的版本依赖 当模块与内核链接时,insmod 会检查模块和当前内核版本是否匹配,每个模块都定义了 版本符号__module_kernel_version,这个符号位于模块文件的 ELF 头的.modinfo 段中。只要在 模块中包含,编译器就会自动定义这个符号。每个内核版本都需要特定版本 的编译器的支持,高版本的编译器并不适合低版本的内核,比如 SinoSys-M3 实验箱中的 LINUX-2.6.13 的内核需要 2.95.3 的 GCC 版本编译器。 Linux-2.6 版本的 insmod 命令装载模块时,首先从/lib/modules 目录和内核相关的子目 录中查找模块文件,如果需要从当前目录装载,使用 insmod module.ko。 5.4 主设备号和次设备号 传统方式中的设备管理中,除了设备类型外,内核还需要一对称作主次设备号的参数,才能 唯一标识一个设备。主设备号相同的设备使用相同的驱动程序,次设备号用于区分具体设备 的实例。比如 PC 机中的 IDE 设备,一般主设备号使用 3,WINDOWS 下进行的分区,一般 将主分区的次设备号为 1,扩展分区的次设备号为 2、3、4,逻辑分区使用 5、6….。 设备操作宏 MAJOR()和 MINOR()可分别用于获取主次设备号,宏 MKDEV()用于将主设备号 和次设备号合并为设备号,这些宏定义在 include/linux/kdev_t.h 中。对于 LINUX 中对设备 号的分配原则可以参考 Documentation/devices.txt。 对于查看/dev 目录下的设备的主次设备号可以使用如下命令: #ls /dev -l crw------- 1 root root 5, 1 Jan 1 00:00 console crw------- 1 root root 5, 64 Jan 1 00:00 cua0 crw------- 1 root root 5, 65 Jan 1 00:00 cua1 crw-rw-rw- 1 root root 1, 7 Jan 1 00:00 full drwxr-xr-x 1 root root 0 Jan 1 00:00 keyboard crw-r----- 1 root root 1, 2 Jan 1 00:00 kmem crw-r----- 1 root root 1, 1 Jan 1 00:00 mem drwxr-xr-x 1 root root 0 Jan 1 00:00 mtd 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 151 页 共 175 页 双实科技 drwxr-xr-x 1 root root 0 Jan 1 00:00 mtdblock crw-rw-rw- 1 root root 1, 3 Jan 1 00:00 null crw-r----- 1 root root 1, 4 Jan 1 00:00 port crw------- 1 root root 108, 0 Jan 1 00:00 ppp crw-rw-rw- 1 root root 5, 2 Jan 1 00:00 ptmx crw-r--r-- 1 root root 1, 8 Jan 1 00:00 random lr-xr-xr-x 1 root root 4 Jan 1 00:00 root -> rd/0 crw-rw-rw- 1 root root 5, 0 Jan 1 00:00 tty crw------- 1 root root 4, 64 Jan 1 00:11 ttyS0 crw------- 1 root root 4, 65 Jan 1 00:00 ttyS1 crw-r--r-- 1 root root 1, 9 Jan 1 00:00 urandom crw-rw-rw- 1 root root 1, 5 Jan 1 00:00 zero 5.5 设备驱动程序接口 通常所说的设备驱动程序接口是指结构 file_operations{},它定义在 include/linux/fs.h 中。 file_operations 数据结构说明 struct file_operations { struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char *, size_t, loff_t *); ssize_t (*write) (struct file *, const char *, size_t, loff_t *); int (*readdir) (struct file *, void *, filldir_t); unsigned int (*poll) (struct file *, struct poll_table_struct *); int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); int (*mmap) (struct file *, struct vm_area_struct *); int (*open) (struct inode *, struct file *); int (*flush) (struct file *); int (*release) (struct inode *, struct file *); int (*fsync) (struct file *, struct dentry *, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *); ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *); ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); #ifdef MAGIC_ROM_PTR int (*romptr) (struct file *, struct vm_area_struct *); #endif }; file_operations 结构是整个 Linux 内核的重要数据结构,它也是 file{}、inode{}结构的重要成 员,表 1 中分别说明结构中主要的成员: 表 1 file_operations 结构 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 152 页 共 175 页 双实科技 Owner Module 的拥有者。 Llseek 重新定位读写位置。 Read 从设备中读取数据。 Write 向字符设备中写入数据。 Readdir 只用于文件系统,对设备无用。 Ioctl 控制设备,除读写操作外的其他控制命令。 Mmap 将设备内存映射到进程地址空间,通常只用于块设备。 Open 打开设备并初始化设备。 Flush 清除内容,一般只用于网络文件系统中。 Release 关闭设备并释放资源。 Fsync 实现内存与设备的同步,如将内存数据写入硬盘。 Fasync 实现内存与设备之间的异步通讯。 Lock 文件锁定,用于文件共享时的互斥访问。 Readv 在进行读操作前要验证地址是否可读。 Writev 在进行写操作前要验证地址是否可写。 在嵌入式系统的开发中,我们一般仅仅实现其中几个接口函数:read、write、ioctl、open、release, 就可以完成应用系统需要的功能。 5.6 file 数据结构说明 struct file { struct list_head f_list; struct dentry *f_dentry; struct vfsmount *f_vfsmnt; struct file_operations *f_op; atomic_t f_count; unsigned int f_flags; mode_t f_mode; loff_t f_pos; unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin; struct fown_struct f_owner; unsigned int f_uid, f_gid; int f_error; unsigned long f_version; void *private_data; struct kiobuf *f_iobuf; long f_iobuf_lock; }; file 结构中与驱动相关的重要成员说明: 我们将 struct file 结构指针定义为 flip,以便于下面说明。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 153 页 共 175 页 双实科技 表 2 file 结构中与驱动相关的成员 f_mode 标识文件的读写权限 f_pos 当前读写位置,类型为 loff_t 是 64 位的数,只能读不能写 f_flag 文件标志,主要用于进行阻塞/非阻塞型操作时检查 f_op 文件操作的结构指针,内核在 OPEN 操作时对此指针赋值。 private_data Open 系统调用在调用驱动程序的 open 方法前,将此指针值 NULL,驱动程 序可以将这个字段用于任何目的,一般用它指向已经分配的数据,但 在内核销毁 file 结构前要在 release 方法中释放内存。 f_dentry 文件对应的目录项结构,一般在驱动中用 filp->f_dentry->d_inode 访问 索引节点时用到它。 5.7 驱动接口的实现过程 我们先看看实验代码框架 #define DEVICE_MAJOR 254 static int demo_major= DEVICE_MAJOR; struct device_dev { struct cdev cdev; ………… }; struct device_dev *demo_devp; int demo_open(struct inode *inode, struct file *filp) { filp->private_data = demo_devp; return 0; } int demo_release(struct inode *inode, struct file *filp) { return 0; } static int demo_ioctl(struct inode *inodep, struct file *filp, unsigned int cmd, unsigned long arg) { …………. return 0; 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 154 页 共 175 页 双实科技 } static ssize_t demo_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos) { ……. } static ssize_t demo_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos) { …….. } static const struct file_operations demo_fops = { .owner = THIS_MODULE, .read = demo_read, .write = demo_write, .ioctl = demo_ioctl, .open = demo_open, .release = demo_release, }; static void demo_setup_cdev(struct demo_dev *dev, int index) { int err, devno = MKDEV(demo_major, index); cdev_init(&dev->cdev, &demo_fops); dev->cdev.owner = THIS_MODULE; dev->cdev.ops = &demo_fops; err = cdev_add(&dev->cdev, devno, 1); if (err) printk(”….”); } int demo_init(void) 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 155 页 共 175 页 双实科技 { int result; dev_t devno = MKDEV(demo_major, 0); if (demo_major) result = register_chrdev_region(devno, 1, "demo"); else { result = alloc_chrdev_region(&devno, 0, 1, "demo"); demo_major = MAJOR(devno); } if (result < 0) return result; demo_devp = kmalloc(sizeof(struct demo_dev), GFP_KERNEL); if (!demo_devp) { result = - ENOMEM; goto fail_malloc; } memset(demo_devp, 0, sizeof(struct demo_dev)); demo_setup_cdev(demo_devp, 0); return 0; fail_malloc: unregister_chrdev_region(devno, 1); return result; } void demo_exit(void) { cdev_del(&demo_devp->cdev); kfree(demo_devp); unregister_chrdev_region(MKDEV(demo_major, 0), 1); } MODULE_AUTHOR("ddd"); MODULE_LICENSE("Dual BSD/GPL"); module_param(demo_major, int, S_IRUGO); 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 156 页 共 175 页 双实科技 module_init(demo_init); module_exit(demo_exit); 其中, static struct file_operations demo_fops = {…}完成了将驱动函数映射为标准接口 z Open 方法 Open 方法提供给驱动程序初始化设备的能力,从而为以后的设备操作做好准备,此外 Open 操作一般还会递增使用计数,用以防止文件关闭前模块被卸载出内核。在大多数驱动程 序中 Open 方法应完成如下工作: 1. 2. 3. 4. 5. 递增使用计数。 检查特定设备错误。 如果设备是首次打开,则对其进行初始化。 识别次设备号,如有必要修改 f_op 指针。 分配并填写 filp->private_data 中的数据。 z Release 方法 与 open 方法相反,release 方法应完成如下功能: 1. 2. 3. 释放由 open 分配的 filp->private_data 中的所有内容。 在最后一次关闭操作时关闭设备。 使用计数减一。 z Read 和 Write 方法 ssize_t demo_write(struct file *filp,const char * buffer, size_t count,loff_t *ppos) ssize_t demo_read(struct file *filp, char *buffer, size_t count, loff_t *ppos) read 方法完成将数据从内核拷贝到应用程序空间,write 方法相反,将数据从应用程序 空间拷贝到内核。对于这两个方法,参数 filp 是文件指针,count 是请求传输数据的长度, buffer 是用户空间的数据缓冲区,ppos 是文件中进行操作的偏移量,类型为 64 位数。由于 用户空间和内核空间的内存映射方式完全不同,所以不能使用象 memcpy 之类的函数,必须 使用如下函数: unsigned long copy_to_user (void *to,const void *from,unsigned long count); unsigned long copy_from_user(void *to,const void *from,unsigned long count); z Read 的返回值 1. 返回值等于传递给 read 系统调用的 count 参数,表明请求的数据传输成功。 2. 返回值大于 0,但小于传递给 read 系统调用的 count 参数,表明部分数据传输 成功,根据设备的不同,导致这个问题的原因也不同,一般采取再次读取的方 法。 3. 返回值=0,表示到达文件的末尾。 4. 返回值为负数,表示出现错误,并且指明是何种错误。 5. 在阻塞型 io 中,read 调用会出现阻塞。 z Write 的返回值 1. 返回值等于传递给 write 系统调用的 count 参数,表明请求的数据传输成功。 2. 返回值大于 0,但小于传递给 write 系统调用的 count 参数,表明部分数据传输 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 157 页 共 175 页 双实科技 4. 成功,根据设备的不同,导致这个问题的原因也不同,一般采取再次读取的方 法。 返回值=0,表示没有写入任何数据。标准库在调用 write 时,出现这种情况会 重复调用 write。 返回值为负数,表示出现错误,并且指明是何种错误。错误号的定义参见 5. 在阻塞型 io 中,write 调用会出现阻塞。 3. z ioctl 方法 ioctl 方法主要用于对设备进行读写之外的其他控制,比如配置设备、进入或退出某种操 作模式,这些操作一般都无法通过 read/write 文件操作来完成,比如在 SinoSys-M3 中的 LED 操作,无法通过 write 操作控制,这就是 ioctl 操作的功能。 用户空间的 ioctl 函数的原型为: int ioctl(inf fd,int cmd,…) 其中的…代表可变数目的参数表,实际中是一个可选参数,一般定义为: int ioctl(inf fd,int cmd,char *argp) 驱动程序中定义的 ioctl 方法原型为: int (*ioctl) (struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg) inode 和 filp 两个指针对应应用程序传递的文件描述符 fd,cmd 不会被修改地传递给驱动程 序,可选的参数 arg 则无论用户应用程序使用的是指针还是其他类型值,都以 unsigned long 的形式传递给驱动。 z ioctl 方法的命令编号确定 由于为了防止向不该控制的设备发出正确的命令,Linux 驱动的 ioctl 方法中的 cmd 参 数推荐使用唯一编号,编号方法并根据如下规则定义: 编号分为 4 个字段: 1. type(类型) :也称为幻数,8 位宽。 2. number(号码):顺序数,8 位宽。 3. direction(方向):如果该命令有数据传输,就要定义传输方向,2 位宽,可使用的数 值: a) _IOC_NONE b) _IOC_READ c) _IOC_WRITE 4. size(大小):数据大小,宽度与体系结构有关,在 ARM 上为 14 位。 这些定义在中可以找到。其中还定义了一些用于构造命令号的宏: #define _IOC_NRBITS 8 #define _IOC_TYPEBITS 8 #define _IOC_SIZEBITS 14 #define _IOC_DIRBITS 2 #define _IOC_NRMASK ((1 << _IOC_NRBITS)-1) #define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1) #define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1) #define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1) 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 158 页 共 175 页 双实科技 #define _IOC_NRSHIFT 0 #define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS) #define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS) #define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS) #define _IOC_NONE 0U #define _IOC_WRITE 1U #define _IOC_READ 2U #define _IOC(dir,type,nr,size) \ (((dir) << _IOC_DIRSHIFT) | \ ((type) << _IOC_TYPESHIFT) | \ ((nr) << _IOC_NRSHIFT) | \ ((size) << _IOC_SIZESHIFT)) #define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0) #define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size)) #define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size)) #define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size)) #define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) #define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK) #define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK) #define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK) 内核目前没有使用 ioctl 的 cmd 参数,所以你如果自己简单定义一个如 1、2、3 这样的 命令号也是可以的。 z ioctl 方法的返回值 I octl 通常实现一个基于 switch 语句的各个命令的处理,对于用户程序传递了不合适的命 名参数时,POSIX 标准规定应返回-ENOTTY,返回-EINVAL 是以前常见的方法。 不能使用与 Linux 预定义命令相同的号码,因为这些命令号码会被内核 sys_ioctl 函数识别, 并且不再将命令传递给驱动的 ioctl。Linux 针对所有文件的预定义命令的幻数为“T”。所以我 们不应使用 TYPE 为”T”的幻数。 5.8 关于阻塞型 IO read 调用有时会出现当前没有数据可读,但是马上就会有数据到达,这时就会使用睡眠 并等待数据的方法,这就是阻塞型 IO,write 也是同样的道理。在阻塞型 IO 中涉及到如何 使进程睡眠、如何唤醒,如何在阻塞的情况查看是否有数据。 z 睡眠与唤醒 当进程等待一个事件时,应该进入睡眠,等待被事件唤醒,这主要是由等待队列这种机 制来处理多个进程的睡眠与唤醒。这里要使用到如下几个函数和结构: 这个结构和函数的定义在文件中。 wait_queue_head_t: struct __wait_queue_head { wq_lock_t lock; 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 159 页 共 175 页 双实科技 struct list_head task_list; #if WAITQUEUE_DEBUG long __magic; long __creator; #endif }; typedef struct __wait_queue_head wait_queue_head_t; 初始化函数 static inline void init_waitqueue_head(wait_queue_head_t *q): 如果声明了等待队列,并完成初始化,进程就可以睡眠。根据睡眠的深浅不同,可调用 sleep_on 的不同变体函数完成睡眠。一般会用到如下几个函数: sleep_on(wait_queue_head_t *queue); interruptible_sleep_on(wait_queue_head_t *queue); sleep_on_timeout(wait_queue_head_t *queue, long timeout); interruptible_sleep_on_timeout(wait_queue_head_t *queue, long timeout); wait_event(wait_queue_head_t queue,int condition); wait_event_ interruptible (wait_queue_head_t queue,int condition); 我们大多数情况下应使用“可中断”的函数,也就是带 interruptible 的函数。还要注意,睡 眠进程被唤醒并不一定代表有数据,也有可能被其他信号唤醒,所以醒来后需要测试 condition。 5.9 并发访问与数据保护 1. 可以使用循环缓冲区并且避免使用共享变量 这种方法是类似于“生产者消费者问题”的处理方法,生产者向缓冲区写入数据,消费者 从缓冲区读取数据。 2. 使用自旋锁实现互斥访问 自旋锁的操作函数定义在文件中。其中包含了许多宏定义,主要的函数 如表 4 所示: 表 4 自旋锁德操作函数 spin_lock_init(lock) 初始化锁 spin_lock(lock) 获取给定的自旋锁 spin_is_locked(lock) 查询自旋锁的状态 spin_unlock_wait(lock) 释放自旋锁 spin_unlock(lock) 释放自旋锁 spin_lock_irqsave(lock, flags) 保存中断状态获取自旋锁 spin_lock_irq(lock) 不保存中断状态获取自旋锁 spin_lock_bh(lock) 获取给定的自旋锁并阻止底半部的执行 Linux 中 还 提 供 了 称 为 读 者 / 写 者 自 旋 锁 , 这 种 锁 的 类 型 为 rwlock_t , 可 以 通 过 文件查看更详细的内容。 5.10 中断处理 中断是所有现在微处理器的重要功能,Linux 驱动程序中对于中断的处理方法一般使用 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 160 页 共 175 页 双实科技 以下几个函数: 请求安装某个中断号的处理程序: extern int request_irq(unsigned int irq,void (*handler)(int, void *, struct pt_regs *),unsigned long flag,const char * dev_name,void *dev_id); 释放中断 extern void free_irq(unsigned int, void *); request_irq 函数中的参数说明如表 5 所示: 表 5 request_irq 函数中的参数说明 irq 请求的中断号 void(*handler)(int,void*,struct pt_regs*) 要安装的处理函数指针 Unsigned long flag 与中断管理相关的位掩码 const char dev_name 用于在/proc/interrupts 中显示的中断的拥有者 用于标识产生中断的设备号。 void *dev_id 其中的 flag 中可以设置的位定义如表 6 所示: 表 6 Flag 的位定义 SA_INTERRUPT 是快速中断程序,一般运行在中断禁用状态 SA_SHIRQ 中断可以在设备之间共享 指出产生的中断对/dev/random 和/dev/urandom 设备 SA_SAMPLE_RANDOM 一般我们应该在设备第一次 open 时使用 request_irq 函数,在设备最后一次关闭时使用 free_irq。 编写中断处理函数的注意事项: 中断处理程序与普通 C 代码没有太大不同,不同的是中断处理程序在中断期间运行,它 有如下限制: z z z 不能向用户空间发送或接受数据, 不能执行有睡眠操作的函数 不能调用调度函数 6、 实验步骤 此实验为蜂鸣器驱动。(实验源码见光盘) 1) 阅读相关书籍,理解驱动的体系结构和接口实现过程。 2) 编写驱动源代码和 Makefile 3) 编写简单的驱动测试程序,以验证驱动的可行性。 4) 改写该驱动程序,在其基础上实现一些你想要的简单功能。由于驱动程序的复杂性, 不容易上手且又容易出问题,所以建议你先只对其中的调试信息做一些改动,在运 行该驱动程序时看看其在屏幕上的打印信息。在你对整个过程及相关硬件有较多的 一些了解之后再动手做一些功能上的调整。 7、 思考题 1) 另外找一个 Linux 的设备驱动程序(在 Linux 源码的 drivers 目录下),剖析它的结 构及工作原理。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 161 页 共 175 页 双实科技 5.2 系统中断实验—键盘中断的实现 1、 实验目的 z 了解 ARM 的中断方式和原理 z 熟悉 Linux 中断驱动程序实现方法。 z 理解底层驱动与上层应用之间的关系。 2、 实验内容 z 剖析键盘中断的实现过程。 z 编写键盘上层应用程序验证中断的实现。 3、 预备知识 z 掌握在 Linux 集成开发环境中编写和调试程序的过程。 z 了解 ARMS3C2440 的基本结构及其中断的工作原理。 z 了解 Linux 内核中关于中断控制的基本原理 4、 实验设备 z 硬件:PC 机 z 软件:Red Hat9 5、 实验原理 5.1 概述 S3C2440A 内置的中断控制器可以接收来自 60 个中断源的请求。中断控制器的角 色,就是响应来自 FIQ(快速中断请求)或 IRQ(普通中断请求)的中断,并请求内 核对 中断进行处理。当有多个中断同时发生时,中断控制器要决定首先处理哪一个中 断。 下面就来详细了解 S3C2440A 的中断控制器。 5.2 中断控制器 5.2.1 中断模式 ARM920T 有 2 种类型的中断模式:FIQ 和 IRQ。IRQ 和 FIQ 之间的区别是:对于 FIQ 必须尽快处理事情并离开这个模式;IRQ 可以被 FIQ 中断,但 IRQ 不能中断 FIQ 。为了 使 FIQ 更快,FIQ 模式具有更多的私有寄存器。 5.2.2 PSR 的 F 位和 I 位 PSR指ARM920T处理器的程序状态寄存器。如果PSR的F位被设置为1,处理器将不接受来 自中断控制器的FIQ;如果PSR的I位被设置为l,处理器将不接受来自中断控制器的IRQ。因此, 为了使能相应中断机制,PSR的F位或I位必须被清0,同时INTMSK(中断屏蔽寄存器)的相应位 也必须被清0。 5.2.3 Pending 寄存器 S3C2440A有两个中断Pending寄存器:SRCPND和INTPND。寄存器中的位表示某一个中断是 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 162 页 共 175 页 双实科技 否未被处理。当一个中断发生时,SRCPND中的对应位将置1,同时在硬件仲裁机制后,只有一 位INTPND被置为1。如果某位中断被屏蔽,SRCPND寄存器依然会置1,但INTPND不会改变。当 INTPND某一位被置1后,如果对应的PSR中的F位和I位被清零,则该中断将被处理。SRCPND和 INTPND寄存器是可读可写的,因此中断处理程序中必须将这两个寄存器中中断对应的位清零。 5.2.4 INTMSK 中断屏蔽寄存器 如果该寄存器的某一个位被置l,则与该位对应的中断响应被禁止。如果某个中断在 INTMSK寄存器的对应位为0,则这个中断发生时将会被正常响应。如果某个中断在INTMSK寄存 器中的对应位为1,但是又有这个中断发生,则它的pending位还是会置位,只是不会自动转 入中断服务程序。如果全局屏蔽位被置1,那么,当任一中断发生时,中断pending位还是会 置位,但是所有的中断都不会得到服务。 5.3 中断源 中断控制器支持60个中断源。有关中断源的详细信息如表1、表2。 Sources INT_ADC ADC EOC and Touch INT_RTC RTC alarm INT_SPI1 SPI1 INT_UART0 UART0 Interrupt INT_IIC Arbiter Descriptions IIC Group interrupt (INT_ADC_S/INT_TC) interrupt ARB5 ARB5 interrupt ARB5 (ERR, RXD, and TXD) ARB5 interrupt ARB4 INT_USBH USB Host interrupt ARB4 INT_USBD USB Device INT_NFCON Nand Flash Control INT_UART1 UART1 Interrupt INT_SPI0 SPI0 interrupt ARB4 INT_SDI SDI interrupt ARB 3 INT_DMA3 DMA channel 3 interrupt ARB3 INT_DMA2 DMA channel 2 interrupt ARB3 INT_DMA1 DMA channel 1 interrupt ARB3 INT_DMA0 DMA channel 0 interrupt ARB3 INT_LCD LCD interrupt (INT_FrSyn and INT_FiCnt) ARB3 INT_UART2 UART2 Interrupt INT_TIMER4 Timer4 interrupt ARB2 INT_TIMER3 Timer3 interrupt ARB2 INT_TIMER2 Timer2 interrupt ARB2 INT_TIMER1 Timer1 interrupt ARB 2 INT_TIMER0 Timer0 interrupt ARB2 interrupt ARB4 Interrupt ARB4 (ERR, RXD, and TXD) ARB4 (ERR, RXD, and TXD) INT_WDT_AC97 Watch-Dog timer INT_TICK RTC Time tick ARB2 interrupt(INT_WDT, INT_AC97) interrupt 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 ARB1 ARB1 第 163 页 共 175 页 双实科技 nBATT_FLT Battery Fault interrupt ARB1 INT_CAM Camera Interface (INT_CAM_C, INT_CAM_P) ARB1 EINT8_23 External interrupt 8 – 23 ARB1 EINT4_7 External interrupt 4 – 7 ARB1 EINT3 External interrupt 3 ARB0 EINT2 External interrupt 2 ARB0 EINT1 External interrupt 1 ARB0 EINT0 External interrupt 0 ARB0 表1 中断源信息 Sub Sources Descriptions Source INT_AC97 AC97 interrupt INT_WDT_AC97 INT_WDT Watchdog interrupt INT_WDT_AC97 INT_CAM_P P-port capture interrupt In camera INT_CAM_C C-port capture interrupt in camera INT_ADC_S ADC interface interface interrupt INT_CAM INT_CAM INT_ADC INT_TC Touch screen interrupt (pen up/down) INT_ERR2 UART2 error interrupt INT_TXD2 UART2 transmit interrupt INT_UART2 INT_RXD2 UART2 receive interrupt INT_UART2 INT_ERR1 UART1 error INT_TXD1 UART1 transmit interrupt INT_UART1 INT_RXD1 UART1 receive interrupt INT_UART1 INT_ERR0 UART0 error INT_TXD0 UART0 transmit interrupt INT_UART0 INT_RXD0 UART0 receive interrupt INT_UART0 interrupt interrupt INT_ADC INT_UART2 INT_UART1 INT_UART0 表2 子中断源信息 5.4 中断优先级产生模块 S3C2440A还提供了另一种通过硬件决定中断优先级的方式——矢量中断模式。在多个中 断源同时请求中断时,硬件优先级逻辑可以决定哪一个中断应该得到响应;然后,这个硬件 逻辑产生一个跳转指令跳到矢量表中对应的中断矢量地址处,在这个地址上事先已经放置了 跳转到与该中断相应的中断服务程序的跳转指令。与前一种软件方式相比,这种方式将大大 减少中断延迟。 中断优先级产生模块如图1所示。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 164 页 共 175 页 双实科技 图1 中断优先级产生模块 5.5 控制中断的寄存器 在实际编程中,通过对这些寄存器进行读取和设置来实现对中断的响应和控制。这些寄 存器包括:中断源请求寄存器(SRCPND)、中断请求寄存器(INTPND)、中断模式寄存器(INTMOD)、 中断屏蔽寄存器(INTMSK)、优先级寄存器(PRIORITY)。具体寄存器的位定义和地址分配 情况可参照S3C2440A处理器的产品手册。 5.6 Linux 操作系统对中断的管理 Linux 内核为了将来自硬件设备的中断传递 到相应的设备驱动程序,在驱动程序初始化 的时候就将其对应的中断程序进行了登记,即通过调用函数 request_irq()将其中断信息添加到 结构为 irqaction 的数组中,从而使中断号和中断服务程序联系起来。 request_irq()函数原型如下: int request_irq(unsigned int irq,void (*handler)(int, void *, struct pt_regs *),unsigned long flag,const char * dev_name,void *dev_id); Free_irq()为释放中断处理函数。 5.7 键盘中断的硬件连接图 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 165 页 共 175 页 双实科技 6、 实验步骤 本实验的目的就是当程序在运行之后,按下开发板上这四个按钮,将触发处理器的四个 外部中断,处理器转而去执行相应的中断服务程序,在中断服务程序中,向串口打印中断信 息,并输出到开发主机的串口终端工具上。 1) 进入光盘目录,使用 vi 编辑器或其他编辑器阅读理解源代码。 2) 剖析键盘中断实现源代码。。 3) 编写驱动程序的测试程序 4) 编译源代码,生成 BIN 文件 5) 下载生成的 BIN 文件到开发板 6) 建立节点,进行驱动模块的加载 7) 运行测试程序进行驱动的测试。 7、 思考题 1) 2) 复习 ARM 中断寄存器的分类与使用 试着分析触摸屏中断代码的实现 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 166 页 共 175 页 双实科技 5.3 CAN 驱动的实现 1、 实验目的 z 了解 CAN 总线的工作机制。 z 掌握在 S3C2440A 平台下进行 CAN 总线通讯编程。 z 了解 MCP2510 芯片,并编写底层驱动。 2、 实验内容 z 理解 CAN 总线的工作机制。 z 了解 MCP2510 芯片 z 编写 MCP2510-CAN 总线的输入与输出的驱动 3、 预备知识 z 掌握在 Linux 集成开发环境中编写和调试程序的过程。 z 了解 ARMS3C2440 的基本结构及其中断的工作原理。 z 掌握在 Linux 下常用的编辑器的使用 z 掌握 Makefile 的编写和使用 z 掌握 Linux 下程序编译与交叉编译过程 z 有驱动开发的基本知识 4、 实验设备 z 硬件:PC 机 z 软件:Red Hat9 5、 实验原理 5.1 概述 在计算机数据传输领域内,长期以来使用 RS-232 通信标准,尽管被广泛的使用,但却 是一种低数据率和点对点的数据传输标准,无能力支持更高层次的计算机之间的功能操作。 同时,在复杂或大规模应用中(如工业现场控制或生产自动化领域),需要使用大量的传感器、 执行器和控制器等,它们通常分布在非常广的范围内,所以,在最底层的确需要一种造价低 廉而又能适应工业现场环境的通信系统,现场总线(Field Bus)就是在这种背景下应运而生 的。 现场总线是连接智能现场设备和自动化系统的数字式、双向传输、多分支结构的通信网 络,现场总线技术自上世纪 70 年代诞生至今,由于它在减少系统线缆,简化系统安装、维护 和管理,降低系统的投资和运行成本,增强系统性能等方面的优越性,引起人们的广泛注意, 得到大范围的推广。 CAN 是一种有效支持分布式控制或实时控制的串行通信网络,最初是由德国 BOSCH 公司 为汽车监控、控制系统设计的。由于 CAN 总线本身的特点,其应用范围目前已不再局限于汽 车行业,而向过程工业、机械工业、纺织机械、农用机械、机器人、数控机床、医疗器械、 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 167 页 共 175 页 双实科技 传感器及智能仪表等领域发展。 5.2 CAN 总线的技术特点 CAN 总线可有效支持分布式控制或实时控制。该总线的通信介质可以是双绞线、同轴电 缆或光纤,其主要特点如下: • CAN 总线为多主站总线,各节点可在任意时刻向网络上的其他节点发送信息,且不分 主从; • CAN 总线采用独特的非破坏性总线仲裁技术,高优先级节点优先传送数据,故实时性 好; • CAN 总线具有点对点、一点对多点及全局广播传送数据的功能; • CAN 总线采用短帧结构,每帧有效字节数最多为 8 个,数据传输时间短,并有 CRC 及 其它校验措施,数据出错率极低; • CAN 总线上某一节点出现严重错误时,可自动脱离总线,而总线上的其他操作不受影 响; • CAN 总线系统扩充时,可直接将新节点挂在总线上,因而走线少,系统扩充容易,改 型灵活; • CAN 总线的最大传输速率可达 1Mb/s,直接通信距离最远可达到 10km(速率在 5kbps 以下); • CAN 总线上的节点数取决于总线驱动电路。在标准帧(11 位报文标识符)时可达到 110 个,而在扩展帧(29 位报文标识符)时,个数不受限。 5.3 CAN 的分层结构 CAN的结构实际上是一种简化的网络结构,按ISO/OSI标准模型CAN可分为数据链路层(含 逻辑链路子层LLC、介质访问控制子层MAC)和物理层。 逻辑链路子层(LLC):提供数据传输和远程数据请求服务,确认报文已接收,提供超载 信息及恢复管理;介质访问控制子层(MAC):承担定时特性,每当新的通信开始前,MAC 子 层要确定总线是否开放或是否马上开始接收。MAC 层规定了传输规则(控制帧结构、执行仲 裁、错误检测、出错标志及故障界定);物理层则规定了结点的全部电器特性。 数据帧结构(见图2)由7个位场构成:帧起始、仲裁场、控制场、数据场、CRC场、应答 场和帧尾。 在 CAN 总线中存在 5 种错误类型,分别为: 位错误:结点在发送每一位的同时对总线进行监视,每当检测到总线的位数值与发送的 位数值不同时,便在该位的时段内检测到一个位错误; 填充错误:在应用位填充方式编码的报文中,如出现 6 个连续相同的位电子,则判断为 一个填充错误; CRC 错误:接收器与发送器以相同的算法计算 CRC 序列,如结果与接收到的 CRC 序列不 同,则检测到一个 CRC 错误; 格式错误:当固定形式的位场中出现一个或多个非法位时,则检测到一个格式错误; 应答错误:在应答时隙内,如发送器未检测到应答显位,则检测到一个应答错误。 5.4 CAN 总线控制器 MCP2510 的简介 MCP2510 是一种带有 SPI 接口的 CAN 控制器,它支持 CAN 技术规范 V2.0A/B;并能 够发送的接收标准的和扩展的信息帧,同时具有接收滤波和信息管理的功能。MCP2510 通过 SI 接口与 MCU 进行数据传输,最高数据传输速率可达 5Mb/s,MCU 可通过 MCP2510 与 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 168 页 共 175 页 双实科技 CAN 总线上的其它 MCU 单元通讯。MCP2510 内含三个发送缓冲器、二个接收缓冲器。同 时还具有灵活的中断管理能力,这些特点使得 MCU 对 CAN 总线的操作变得非常简便。 ¾ MicroChipٛ公司的MCP2510 CAN总线控制器,其特点如下: - 0 - 8 字节报文长度 - 标准和扩展数据帧 - 可编程位传输速率可达1 Mb/s - 支持远程帧 - 两个接收缓冲器, 可优先储存报文 - 六个完全验收滤波器 - 两个完全验收屏蔽滤波器 - 三个发送缓冲器,具有优先级设定以及发送中止功能 - 用于自检的环回模式 ¾ MCP2510 的引脚功能 引脚 名称 功 能 1 TXCAN 去CAN 总线的发送输出引脚 2 RXCAN 来自CAN 总线的接收输入引脚 3 CLKOUT 具有可编程预分频的时钟输出引 脚 4 5 6 TX0RTS TX1RTS TX2RTS 发送缓冲器发送请求端,或作数 字输入端 7 8 OSC2 OSC1 振荡器输出端、输入端 9 Vss 地端 10 11 RX1BF RX0BF 接收缓冲器中断引脚,或作数字 输出端 12 INT 中断输出引脚 13 SCK SPI 接口的时钟输入端 14 SI SPI 接口的数据输入端 15 SO SPI 接口的数据输出端 16 CS SPI 接口的片选输入端 17 RESET 复位端 18 VDD 电源端 ¾ 收发操作 MCP2510 的发送操作通过三个发送缓冲器来实现。这三个发送缓冲器各占据14 个字节的 SRAM。第一字节是控制寄存器TXBNCTRL,该寄存器里的内容设定了信息发送的条件,且给出 了信息的发送状态;第二至第六字节用来存放标准的和扩展的标识符以及仲裁信息;最后八个字 节则用来存放待发送的数据信息。在进行发送前,必须先对这些寄存器进行初始化。 ¾ 中断管理 MCP2510 有8 个中断源,包括发送中断、接收中断、错误中断及总线唤醒中断等。利用 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 169 页 共 175 页 双实科技 中断使能寄存器CANINTE 和中断屏蔽寄存器CANINTF 可以方便地实现对各种中断的有效管 理。当有中断发生时,INT 引脚变为低电平并保持在低电平,直到MCU 清除中断为止。 ¾ 错误检测 CAN 协议具有CRCF 错误、应答错误、形式错误、位错误和填充错误等检测功能。MCP2510 内含接收出错计数器(REC)和发送出错计数器(TEC)两个错误计数器。因而对于网络中的任 何一个节点来说,都有可能因为错误计数器的数值不同而使其处于错误-激活、错误-认可和总线脱离三种状态之一。 ¾ SPI接口操作时序 具体的SPI接口操作时序参阅MCP2510的数据手册,在这就不详细说明了。 5.5 CAN 总线设备硬件原理图 通 过 使 用 S3C2440A 的 通 用 IO 口 来 模 拟 SPI 的 输 出 同 MCP2510 相 连 接 , 通 过 对 MCP2510 寄 存 器 的 配 置 和 操 作 实 现 CAN 总 线 数 据 输 入 输 出 功 能 。 6、 实验步骤 本实验的目的就是 can 总线芯片 MCP2510 的驱动,通过应用回环模式,进行测试程序 的编写,从而进行驱动程序的测试。 1) 2) 3) 4) 5) 6) 进入光盘目录,使用 vi 编辑器或其他编辑器阅读理解源代码。 编写驱动程序的测试程序 编译源代码,生成 BIN 文件 下载生成的 BIN 文件到开发板 建立节点,进行驱动模块的加载 运行测试程序进行驱动的测试。 7、 思考题 1、 CAM 总线通信至少需要几根线?如果多个节点应该如何连接? 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 170 页 共 175 页 双实科技 2、 为什么 CAN 总线的可靠性高。传输速率却可以比串口快? 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 171 页 共 175 页 双实科技 5.4 SD 驱动使用实验 1、 实验目的 z 掌握 SD 卡规范的概念 z 学习 SD 卡驱动的基本流程 z 掌握 SD 卡驱动的使用 2、 实验内容 z 根据所提供的 SD 卡原理图、SD 卡的读写时序、SD 规范理解 SD 的驱动函数。 3、 预备知识 z 仔细阅读 SD 卡规范 z SD 卡读写等操作的时序 z 理解 SD 卡驱动 4、 实验设备 z 硬件:PC 机 z 软件:Red Hat9 5、 实验原理 5.1. SD 记忆卡系统概念 SD 记忆卡提供的应用设计有一个低耗的存储设备,作为一个可移动卡执行,对于版权保 护和压缩,解压缩和接口执行提供高安全性保证。 根据它们的功能可以被分为几类(通过 SD 记忆卡系统的指令集): 1.读/写存储器(Flash, OTP, MTP) 这些存储器可作为典型的空白的媒体和数据存储器,用户记录的影象,音频或数字图象。 2.只读存储器(ROM) 这些存储器生产时里面有固定的数据内容。它们被广泛用于分布式的软件分布,影象, 音频等。由于支持电压不同,SD 卡被分为两种: (1)SD 记忆卡支持范围在 2.0-3.6v 初始化/确定的程序,在这个范围的工作电压被定 义在 CSD 的寄存器中。 (2)SDLV 记忆卡-低电压的 SD 存储卡,可以在 1.6-3.6V 之间的电压范围内工作。SDLV 记忆卡和 SD 记忆卡一样也有很多分类。 SD 记忆卡系统包括 SD 记忆卡(或几种卡),总线和它们的主机/应用程序。主机和应用 程序的规范说明超过文档规模。下面各部分提供了对于 SD 记忆卡系统的概述,总线拓扑和通 讯协议。版本保护(安全性)系统描述由“SD 记忆卡安全规范说明”提供。 5.2. 总线拓扑 SD 存储卡系统定义了两种不相容的通信协议:SD 和 SPI。软件可以自行选择其中任意一 种。选定的模式对主机透明。卡可以自动检测到模式重起指令,并在此模式下完成进一步的 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 172 页 共 175 页 双实科技 通信。而且,只使用一种通信模式的软件也不必关心其他模式的情况。 5.3. SD 总线 SD 卡总线包含了如下信号: CLK:主机发来的时钟信号 CMD:1 位指令/响应信号 DAT0-DAT3:4 位数据信号 VDD、VSS1、VSS2:电源和接地信号 SD 存储卡总线有单一的主应用软件,多块从卡,一致的星型拓扑结构(参见数据 2) 。所 有的卡都有相同的时钟,电源和接地信号。指令(CMD)和数据(DAT0-DAT3)信号被指派给 每块卡,以向所有的卡提供连续的点到点联络。 在把初始化指令单独的发送给每块 SD 卡时,允许软件检测每一块卡,并给每个物理接口 分配一个逻辑地址。数据总是在单独的一块卡上收发。但是,为了方便处理卡的堆栈,在初 始化之后,所有的指令可能会被同时发给所有的卡。地址信息由指令包提供。 SD 总线容许动态配置数据总线宽度。根据缺省设置,在启动后,SD 存储卡会只用 DAT0 来传递数据。在初始化之后,主机可以改变总线宽度(活动数据线的条数)。这一特点可以在 HW 成本和系统表现上取得良好的平衡。注意:当不使用 DAT1-DAT3 时,主机与之相关的 DAT 线应当处于输入模式。 5.4. SD 记忆卡 – 引脚和寄存器 SD 存储卡大小为 24mm×32mm×2.1mm。 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 173 页 共 175 页 双实科技 数字描述了关于 SD 卡形状、接口物理属性的一般情况。下面的表格定义了记忆卡的属性: 每块卡都有一套信息寄存器(也可参见《SD 存储卡物理层详述》的第五章) 5.5. SD 卡的硬件连接图 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 174 页 共 175 页 双实科技 6、 实验步骤 进入光盘目录,使用 vi 编辑器或其他编辑器阅读理解源代码。 编译内核,使 SD 卡驱动编译进内核 测试 SD 卡 当设备正确检测到 SD 卡并识别后,我们就可以通过 mount 命令来挂载我们的 SD 卡了。挂载成功后我们可以使用 cp、mkdir、rm 等命令对 SD 卡上的文件进行操作。 1、 2、 3、 7、 思考题 1) 复如果在 SD 总线上接入两个 SD 设备,电路、驱动程序要进行怎样的修改? 上 海 张 江 高 科 技 园 区 毕 升 路 299 弄 3 号 楼 202 室 电 话 : 86-21-33932278 邮 件: supports@sinosys.com.cn 网 址: www.sinosys.com.cn 传 真 : 86-21-33932273 第 175 页 共 175 页