高等学校嵌入式系统设计教材 ARM9处理器C语言编程标准教程 侯殿有 才华 编著 人民邮电出版社
第一章 ARM技术简介 1.1 ARM处理器简介 ARM处理器是一种低功耗高性能的32位RISC (精简指令系统)处理器。本章将其从结构入手进行分析,基于目前流行的ARM920T核详细描述其硬件结构和编程。 ARM处理器共有31个32位寄存器,而其中16个可以在任何模式下看到。它的指令为简单的加载与存储指令(从内存加载某个值,执行完操作后再将其放回内存)。ARM一个有趣的特点是它所有的指令都带有条件。例如用户可以测试某个寄存器的值,但是直到下次使用同一条件进行测试时,才能有条件地执行这些指令。另一个特征是可以在加载数值的同时进行算术和移位操作。它可以在几种模式下操作,包括通过使用SWI(softwarinterrupt软件中断)指令从用户模式进入到系统模式。
ARM处理器是一个综合体,ARM公司自身并不制造微处理器。它们是由ARM的合作伙伴(Intel或LSI)制造。ARM还允许将其处理器通过协处理器接口进行紧耦合。它还包括几种内存管理单元的变种,包括简单的内存保护到复杂的页面层次。 ARM微处理器系列包括ARM7系列、ARM9系列、ARM9E系列、ARM10E系列、SecurCode系列和Intel的Xscale。其中,ARM7、ARM9、ARM9E和ARM10E为4个通用处理器系列,每一个系列提供一套相对独特的性能来满足不同应用领域的需求。例SecurCore系列专门为安全要求较高的应用而设计。
1.1.1 ARM7系列微处理器 ARM7系列微处理器是低功耗的32位RISC处理器,最适合用于对价位和功耗要求较低的消费类应用。ARM7系列有如下特点: · 具有嵌入式ICE—RT (Internet Communications Engine-Route因特网通信)逻辑,调试开发方便。 · 极低的功耗,适合对功耗要求较低的应用,如便携式产品。 · 能够提供0.9MIPS(Million Instructions Per Second百万条/秒)/MHz的三级流水线结构。 · 对操作系统的支持广泛,如Windows CE、Linux、Palm OS等。 · 指令系统与ARM9系列、ARM9E系列和ARM10E系列兼容,便于用户的产品升级换代。 · 主频最高可达130MHz,高速的运算处理能力能胜任绝大多数的复杂应用。
ARM7系列微处理器主要应用于工业控制、Internet设备、网络和调制解调器设备、 移动电话等多种多媒体和嵌入式应用。 ARM7系列微处理器包括如下几种类型的核:ARM7TDMI、ARM7TDMI-S、ARM720T、ARM7EJ。其中,ARM7TDMI是目前使用最广泛的32位嵌入式RISC处理器,属低端ARM处理器核。TDMI的基本含义如下: · T 支持16位压缩指令集Thumb(ARM体系结构中一种16位的指令集)。 · D 支持片上Debug。 · M 内嵌硬件乘法器(Multiplier)。 · I 嵌入式ICE,支持片上断点和调试点。
1.1.2 ARM9系列微处理器 ARM9系列微处理器在高性能和低功耗特性方面提供最佳的表现。具有以下特点: · 5级流水,指令执行效率更高。 · 提供1.1MIPS/MHz的哈佛结构。 · 支持32位ARM指令集和16位Thumb指令集。 · 支持32位的高速AMBA(Advanced Microcontroller Bus Architecture)总线接口。 · 全性能的MMU,支持WindowsCE、Linux、Palm OS等多种主流嵌入式操作系统。 · MPU支持实时操作系统。 · 支持数据Cache(高速缓冲存储器)和指令Cache,具有更高的指令和数据处理力。 ARM9系列微处理器主要应用于无线设备,仪器仪表,安全系统,机顶盒,高端打印机,数字照相机和数字摄像机等。 ARM9系列微处理器包括ARM920T、ARM922T和ARM940T三种类型,以适用于不同的应用场合。
1.1.3 ARM9E系列微处理器 ARM9E系列微处理器的主要特点如下: · 支持DSP指令集,适合于需要高速数字信号处理的场合。 · 5级流水线,指令执行效率更高。 · 支持32位ARM指令集和16位Thumb指令集。 · 支持32位的高速AMBA总线接口。 · 支持VFP9浮点处理协处理器。 · 全性能的MMU,支持众多主流嵌入式操作系统。 · 支持数据Cache和指令Cache,具有更高的处理能力。 · 主频最高可达300MHz。 ARM9E系列微处理器主要应用于下一代无线设备、数字消费品、成像设备、工业控制、存储设备和网络设备等领域。 ARM9E系列微处理器包含ARM926EJ-S、ARM946E-S和ARM966E-S三种类型,以适用于不同的应用场合。
1.1.4 ARM10E系列微处理器 ARM10E系列微处理器的主要特点如下: · 支持DSP指令集,适合于需要高速数字信号处理的场合。 · 6级流水线,指令执行效率更高。 · 支持32位ARM指令集和16位Thumb指令集。 · 支持32位的高速AMBA总线接口。 · 支持VFP10浮点处理协处理器。 · 全性能的MMU,支持众多主流嵌入式操作系统。 · 支持数据Chche和指令Chche,具有更高的处理能力。 · 主频最高可达400MHz。 · 内嵌并行读/学操作部件。 ARM10E系列微处理器主要应用于下一代无线设备、数字消费品、成像设备、工业控制、通信和信息系统等领域。 ARM10E系列微处理器包括ARM1020E、ARM1002E和ARM1026JE-S三种类型,以适用于不同的应用场合。
1.1.5 ARM920T简介 ARM920T高缓存处理器是ARM9 Thumb系列中高性能的32位单片系统处理器。 · ARM9TDMI:只有内核。 · ARM940T:由内核、高速缓存和内存保护单元(MPU)组成。 · ARM920T:有内核、高速缓存和内存管理单元(MMU)组成。 ARM920T提供完善的高性能CPU子系统,包括以下方面: · ARM9TDMI RISC 整数CPU。 · 16K字节指令与16K字节数据缓存。 · 指令与数据存储器管理单元(MMU)。 · 写缓冲器。 · 高级微处理器总线架构(AMBA)总线接口。 · ETM(内置追踪宏单元)接口。
ARM920T中的ARM9TDMI内核可执行32位ARM及16位Thumb指令集。ARM9TDMI处理器是哈佛结构,有包括取指、译码、执行、存储及写入的5级流水线。 · CP14:控制软件对调试信道的访问。 · CP15:系统控制处理器,提供16个额外寄存器来配置与控制缓存、MMU、系统保护、 时钟模式及其他系列选项。 ARM920T处理器的主要特征如下。 · ARM9TDMI内核,ARM v4T架构。 · 两套指令集:ARM高性能32位指令集和Thumb高代码密度16位指令集。
·5级流水线结构,即取指(F)、指令译码(D)、执行(E)、数据存储访问(M)和写寄存器(W)。 · 16K字节数据缓存,16K字节指令缓存。 · 写缓冲器:16字的数据缓冲器,4地址的地址缓冲器,软件控制消耗。 · 标准的ARMv4存储器管理单元(MMU):区域访问许可,允许以1/4页面大小对页面进行访问,16个嵌入域,64个输入指令TLB及64个输入数据TLB。 · 8位、16位、32位的指令总线与数据总线。
1.1.6 SecurCore (可靠内核技术)系列微处理器 SecurCore系列微处理器除了具有ARM体系结构各种主要特点外,在系统安全方面具有如下特点: .带有灵活的保护单元,确保操作系统和应用数据的安全。 .采用软内核技术,防止外部对其进行扫描探测。 .可集成用户自己的安全特性。 SecurCore系列微处理器主要应用于一些对安全性要求较高的应用产品及应用系统,如电子商务、电子政务、电子银行业务、网络和认证系统等领域。 SecurCore系列微处理器包含SecurCore SC100、SecurCore SC110、SecurCore SC200和SecurCour SC210四种类型,以适用于不同的应用场合。
1.1.7 StrongARM (超强性能ARM技术)系列微处理器 Intel StrongARM SA-1100处理器是采用ARM体系结构高度集成的32位RISC微处理器。它融合了Intel公司的设计和处理技术,以及ARM体系结构的电源效率,采用在软件上兼容ARMv4体系结构,同时采用具有Intel技术优点的体系结构。Intel StrongARM处理器是便捷式通信产品和消费类电子产品的理想选择,已成功应用于多家公司的掌上电脑系列产品。
1.2 ARM体系结构的发展 1.2.1 ARM体系结构的发展 在过去的十年中,ARM处理器经历了从简单的ARM7TDMI内核发展到最新ARM11EJ-S内核,ARM当前有5个产品系列——ARM7、ARM9、ARM9E、ARM10、 SecurCore和ARM11。 从简单的三级流水线到先进的8级流水线结构。用单个时钟来进行比较,性能差别不大。 ARM11是ARM家族中性能最强的一个系列。 ARM7TM 通常只能在200MHz以下的频率运行;ARM11系列处理器展示了在性能上的巨大提升,首先推出350M~500MHz时钟频率的内核,在未来将上升到1GHz时钟频率。 ARM11处理器在提供高性能的同时,也允许在性能和功耗间做权衡以满足某些特殊应用。通过动态调整时钟频率和供应电压,开发者完全可以控制这两者的平衡。在0.13um工艺,1.2v条件下,ARM11处理器的功耗可以低至0.4mW/MHz。
ARMv6结构体系: ARM11处理器的超强性能是由一系列的架构特点所决定的。ARMv6是决定性能的基础。 总的来说,ARMv6架构通过以下几点来增强处理器的性能: .多媒体处理功能扩展 .MPEG4编码/解码加快一倍 .音频处理加快一倍 .增强的Cache结构 .实地址Cache .减少Cache的刷新和重载 .减少上下文切换的开销 .增强的异常和中断处理 .使实时任务的处理更加迅速 .使数据共享、软件移植更简单,也有利于节省存储器空间
对绝大多数应用来说,ARMv6保持了100%的二进制向下兼容,使用户过去开发的程序可以进一步继承下去。ARMv6保持了所有过去架构中的T(Thumb指令)和E(DSP指令)扩展,使代码压缩和DSP处理特点得到延续;为了加速Java代码执行速度的ARM Jazalle技术也继续在ARMv6架构中发挥重要作用。
1.2.2 ARM11处理器的内核特点 ARM11是为了更有效的提高处理器能力而设计的。该系列主要有ARM1136J、ARM1156T2和ARM1176JZ三个内核型号 ,ARM11处理器使用130nm工艺,在2.2mm芯片面积上和0.24mW/MHz的前提下主频高达500MHz。ARM11处理器以消费产品市场为目标,推出了许多新的技术,包括针对多媒体处理的SIMD(Single instruction Multiple Data 单指令多数据流),用以提高安全性能的TrustZone(通过硬件和软件结合,为片上数据提供安全环境)技术,智能能源管理IEM(In-Ear Monitoring 耳内监听),以及非常高的、超过2600倍 Dhrystone 2.1标准(测量处理器的运算能力标准) MIPS(百万条指令/每秒) 性能的多处理器技术。
上面对几个ARM处理器内核做了简单的介绍。可以注意到,随着处理器内核技术的发展,处理器的速度越来越快,其主要得益于ARM流水线的技术发展。 ARM1176JZF-S处理器专门用于包括数字电视、机顶盒、游戏机以及手机在内的家电产品和无线产品。这一处理器采用ARM Java加速技术、ARM TrustZone技术以及一个矢量浮点(VFP)协处理器,为嵌入式3D图像提供强大的加速功能。
1.2.3 DSP功能 DSP(digital singnal processor)是一种独特的微处理器,是以数字信号来处理大量信息的器件。其工作原理是接收模拟信号,转换为0或1的数字信号,再对数字信号进行修改、删除、强化,并在其他系统芯片中把数字数据解译回模拟数据或实际环境格式。它不仅具有可编程性,而且其实时运行速度可达每秒数以千万条复杂指令程序,远远超过通用微处理器,是数字化电子世界中日益重要的电脑芯片 目前有很多应用要求多处理器的配置(多个ARM内核,或ARM+DSP的组合),ARM11处理器从设计伊始就注重更容易地与其他处理器共享数据,以及从非ARM的处理器上移植软件。此外,ARM还开发了基于ARM11系列的多处理器系统——MPCORE(由二个到四个ARM11内核组成)。
1.3 ARM体系结构的存储器格式 首先来了解ARM体系结构中的字长: . 字(Word),在ARM体系结构中,字的长度为32位,而在8位/16位处理器体系结构中,字的长度一般为16位。 .半字(Half Word),在ARM体系结构中,半字的长度为16位,与8位/16位处理器体系结构中字的长度一致。 .字节(Byte),在ARM体系结构和8位/16位处理器体系结构中,字节的长度均为8位。 指令长度可以是32位(ARM状态下),也可以为16位(Thumb状态下)。 ARM920T中支持字节(8位)、半字(16位)、字(32位)3种数据类型,其中,字需要4字节对齐,半字需要2字节对齐。 ARM920T体系结构将存储器看成是从零地址开始的字节的线性组合。从0字节到3字节放置第1个存储的字数据,从第4个字节到第7个字节放置第2个存储的字数据,依次排列。
作为32位的微处理器,ARM920T体系结构所支持的最大寻址空间位4GB(2字节)。 ARM920T体系结构支持两种方法存储字数据,即大端(Big Enddian )格式和小端(Little Enddian )格式。在大端格式中,字数据的高字节存储在低字节单元中,而字数据的低字节则存放在高地址单元中,如图1.1所示。 在小端存储格式中,低地址单元存放的是字数据的低字节,高地址单元中,存放的是数据的高字节,如图1.2所示。 在基于ARM920T内核的嵌入式系统中,常用小端存储格式来存储字数据。
第一章习题与练习 1,嵌入式控制系统按操作系统分,大致可分哪几类,每类的设计方法有什么不同? 2,嵌入式控制不加嵌入式操作系统支持,遇到多线程或局域网问题如何解决? 3,ARM体系中的字,半字和字节各占多少位(bit)? 4, 什么是大端存储 (Big Enddian ) 格式和小端存储 (Little Enddian ) 格式,ARM920T内核的嵌入式系统中,常用哪种存储格式来存储字数据? 5, 什么是Thumb指令集?它和32位ARM指令集的区别?
第二章ADS 1.2开发环境创建与简介 2.1 ADS1.2开发环境创建 2.1.1 ADS1.2概述 1. 编译器 ADS是个集成开发环境,主要包括编译器、链接器、调试器、C和C++库等,是ARM公司推出的新一代ARM集成开发工具。最新版本是ADS1.2,该版本支持包括Windows和Linux在内的多种操作环境。ADS1.2的组成如下所述。 1. 编译器 ADS提供多种编译器,以支持ARM和Thumb指令的编译,主要有: · armcc:是ARM C编译器。 · tcc:是Thumb C编译器。 · armcpp:是ARM C++编译器。 · tcpp:是Thumb C++编译器。 · armasm:是ARM和Thumb的汇编语言编译器。
2. 链接器 armlink是ARM链接器。该命令既可以将编译得到的一个或多个目标文件和相关的一个或多个库文件进行链接,生成一个可执行文件,也可以将多个目标文件部分链接成一个目标文件,以供进一步的链接。 3 符号调试器 armsd是ARM和Thumb的符号调试器,能进行源码级程序调试。用户可以在用C或汇编语言写的代码中进行单步调试、设置断点、查看变量值和内存单元的内容。
4 fromELF 将ELF格式的文件转换为各种格式的输出文件,包括BIN格式映像文件、Motorola32位S格式映像文件、Intel32位格式映像文件和Verilog十六进制文件。FromELF命令也能够为输入映像文件产生文本信息,例如代码和数据长度。 5 armar armar是ARM库函数生成器,它将一系列ELF格式的目标文件以库函数的形式集合在一起。用户可以把一个库传递给一个链接器以代替几个ELF文件。
6 CodeWarrior CodeWarrior集成开发环境(IDE)为管理和开发项目提供了简单多样化的图形用户界面,用户可以使用ADS的CodeWarriorIDE为ARM和Thumb处理开发用C、C++或者ARM汇编语言编写的程序代码。 7 调试器 ADS中含有3个调试器,即AXD、Armsd和ADW/ADU。 在ARM体系中,可以选择多种调试方式,如Multi-ICE(Multi-processor In-Circuit Emulator)、ARMulator或Angel。 Multi-ICE是一个独立的产品,是ARM公司自己的JTAG在线仿真器,不是由ADS提供的。
ARMulator是一个ARM指令集仿真器,集成在ARM的调试器AXD中,提供对ARM处理器的指令集的仿真,为ARM和Thumb提供精确的模拟。用户可以在硬件尚未做好的情况下开发程序代码,利用模拟器方式调试。 · Angel是ARM公司常驻在目标机Flash中的监控程序,只需通过RS-232C串口与PC主机相连,就可以对基于ARM架构处理器的目标机进行监控器方式的调试。 C和C++库
ADS提供ANSI C库函数和C++库函数,支持被编译的C和C++代码。用户可以把C库中的与目标相关的函数作为自己应用程序中的一部分,重新进行代码的实现。这就为用户带来了极大的方便,针对自己的应用程序的要求,对与目标无关的库函数进行适当的裁剪。在C库中有很多函数是独立于其他函数的,并且与目标硬件没有任何依赖关系。对于这类函数,用户可以很容易地在汇编代码中使用。 有了这些部件,用户就可以为ARM系列的RISC处理器编写和调试自己的开发应用程序了。
2.1.2 ADS1.2的安装 ADS全称为ARM Developer Suite,是ARM公司推出的新的一代ARM集成开发工具。现在ADS的最新版本是1.2,它取代了早期的ADS1.1和ADS1.0,该版本支持包Windows和Linux在内的多种操作系统。安装步骤如下: 在ADS1.2的安装盘中运行setup.exe,安装ARM Developer Suite v1.2。出现图2-1对话框和图2-2对话框,同意产权协义,选省缺安装路径(C:\Program Files\ARM\vADS1.2)和典型安装模式(Typiflcation),按Next进入下一步,出现选文件夹、编程语言和当前设定对话框,均按Next,开始安装,如图2-3示。 安装结束,安装许可文件(Install License),这一步可按安装向导进行,单击“下一步”按钮,会出现如图2-4和图2-5所示的对话框。
在图2-5对话框中选浏览(Browser)查许可文件,在Program Files\ARM\ADSV1_2\license\中选license.dat文件并打开,单击“下一步”按钮,如图2-6,即可完成ADS1.2的安装。 最后,程序还要注册,注册文件在Program Files\ARM\ADSV1_2文件夹中,单击注册文件,即完成程序注册,如图2-7所示。
2.2 ADS集成开发环境的使用 2.2.1建立一个新工程 运行ADS1.2集成开发环境(CodeWarrior for ARM Developer Suite),点击File|New,在New对话框中,共有7项,ARM Executable Image是ARM的通用模板。选中它即可生成ARM的执行文件,如图2-8所示。
还要在Project name栏中输入项目的名称,以及在Location中输入其存放的位置,按确定保存项目。 2.2.2 开发环境设置 在新建的工程中,选择Debug版本,如图2-9,使用Edit|Debug Settings菜单对Debug版本进行参数设置。
在如图2-10中,点击Debug Setting 按钮,弹出2-11图,选中Target Setting
项,在Post-linker栏中选中ARM fromELF项。按OK确定。这是为生成可执行的代码的初始开关。 3 项,在Post-linker栏中选中ARM fromELF项。按OK确定。这是为生成可执行的代码的初始开关。 3. 在如图2-12中,点击ARM Assembler ,在Architecture or Processer
栏中选ARM920T。这是项目选择的CPU类型。 4 栏中选ARM920T。这是项目选择的CPU类型。 4. 在如图2-13中,点击ARM C Compliler ,在Architecture or Processer栏中选ARM920T。这是要编译的CPU核。
5. 在如图2-14中,点击ARM linker ,在outpur栏中设定程序的代码段地址,以及数据使用的地址。图中的RO Base栏中填写程序代码存放的起始地址,RW Base栏中填写程序数据存放的起始地址。该地址是属于SDRAM的地址。
在options栏中,如图2-15,Image entry point要填写程序代码的入口地址,其他保持不变,如果是在SDRAM中运行,则可在0x30000000—0x33ffffff中选值,这是64M SDRAM的地址,但是这里用的是起始地址,所以必须把你的程序空间给留出来,并且还要留出足够的程序使用的数据空间,而且还必须是4字节对齐的地址(ARM状态)。通常入口点Image entry point 为0x30000000,ro_base也为0x30000000。 在Layout栏中,如图2-16,在Place at beginning of image框内,需要填写项目的入口程序的目标文件名,如,整个工程项目的入口程序是2410init.s,那么应在Object/Symbol处填写其目标文件名2410init.o,在Section处填写程序入口的起始段标号。它的作用是通知编译器,整个项目的开始运行,是从该段开始的。
6. 在如图2-17中,即在Debug Setting对话框中点击左栏的ARM fromELF项,在Output file name栏中设置输出文件名*.bin,前缀名可以自己取,在Output format 栏中选择Plain binary,这是设置要下载到flash中的二进制文件。图2-17中使用的是test.bin。
7. 到此,在ADS1.2中的基本设置已经完成,可以将该新建的空的项目文件作为模板保存起来。首先,要将该项目工程文件改一个合适的名字,如S3C2410 ARM.mcp等,然后,在ADS1.2软件安装的目录下新建一个合适的模板目录名,如,S3C2410 ARM Executable Image,再将刚刚设置完的S3c2410 ARM.mcp项目文件存放到该目录下即可。 8. 新建项目工程后,就可以执行菜单Project|Add Files把和工程所有相关的文件加入,ADS1.2不能自动进行文件分类,用户必须通过Project|Create Group来创建文件夹,然后把加入的文件选中,移入文件夹。或者鼠标放在文件填加区,右键点击,如图2-18所示。
先选Add Files,加入文件,再选Create Group,创建文件夹,然后把文件移入文件夹内。读者可根据自己习惯,更改Edit|Preference窗口内关于文本编辑的颜色、字体大小,形状,变量、函数的颜色等等设置。如图2-19。
2.2.3 ADS1.2下仿真、调试 在ADS1.2下进行仿真调试,首先需要一根仿真调试电缆和JTAG仿真器,用调试电缆把 JTAG仿真器和上位机并口相连, JTAG仿真器的驱动程序为两个动态链接库,也要事先安装。 打开调试软件AXD Debugger。点击File|load image 加载可执行文件xx.axf,打开超级终端,设置其参数为:波特率为115200,数据位数8,奇偶校验无,停止位无1,数据流控无。点击全速运行,在我们的例子程序中,出现图2-20的界面:
最后介绍调试按钮,调试按钮在程序进入AXD Debugge状态时会出现在主菜单项,主要几个调试按钮如图2-21所示。 图2-21,左起第一个是全速运行,第二个是停止运行,第三个跳入函数内部单步执行,第四个把一个函数做为一个语句单步执行,第五个跳出函数。 关于在ADS1.2下进行仿真调试,下面还要祥细介绍。
2.2.4 其他开发环境介绍 IAR(瑞典爱亚软件技术咨询公司) Embedded Workbench for ARM 是IAR Systems 公司为ARM 微处理器开发的一个集成开发环境,下面简称IAR EWARM。比较其他的ARM 开发环境,IAR EWARM 具有入门容易、使用方便和代码紧凑等特点。故在这里做简单介绍。 IAR Systems 公司目前推出的最新版本是IAR Embedded Workbench for ARM version 4.42,并提供一个32k 代码限制学习版或30 天时间限制的免费评估版,可以到IAR 公司的网站www.iar.com/ewarm 下载。 IAR EWARM 中包含一个全软件的模拟程序(simulator)。用户不需要任何硬件支持就可以模拟各种ARM内核、外部设备甚至中断的软件运行环境。从中可以了解和评估IAR EWARM 的功能和使用方法。
IAR EWARM 中包含一个全软件的模拟程序(simulator)。用户不需要任何硬件支持就可以模拟各种ARM内核、外部设备甚至中断的软件运行环境。从中可以了解和评估IAR EWARM 的功能和使用方法。 IAR Embedded Workbench for ARM version 4.42 是一个针对ARM 处理器的集成开发环境,包含项目管理器、编辑器、编译连接工具和支持RTOS(嵌入式实时控制系统)的调试工具,在该环境下可以使用C/C++和汇编语言方便地开发嵌入式应用程序。IAR EWARM 的主要模块如下: .项目管理器 .功能强大的编辑器 .高度优化的IAR ARM C/C++ Compiler .IAR ARM Assembler .1 个通用的IAR XLINK Linker .IAR XAR 和XLIB 建库程序和IAR DLIB C/C++运行库 .IAR C-SPY 调试器(先进的高级语言调试器) .命令行实用程序
以下介绍一下EWARM 4. 42 版本及其相关配套硬件的一些特点: 1. IAR EWAM 软件的特点 ① EWARM 4 以下介绍一下EWARM 4.42 版本及其相关配套硬件的一些特点: 1. IAR EWAM 软件的特点 ① EWARM 4.42 版基本特点 . 完善的ARM 内核支持 .最新支持到ARM11 及Cortex M3 内核 .支持的其他ARM 内核 .ARM7(ARM7TDMI,ARM7TDMI-S,ARM720T) .ARM9(ARM9TDMI,ARM920T,ARM922T,ARM940T,ARM9E,ARM9E-S, ARM926EJ-S,ARM946E-S,ARM966E-S,ARM968E-S) .ARM10(ARM10E,ARM1020E,ARM1022E,ARM1026EJ-S) .XScale(XScale,XScale-IR7) .
更加客户化地提供芯片级的支持 .完备的各厂商ARM 处理器的C/C++和汇编语言外设寄存器定义文件 支持的芯片厂商有Analog Devices、ARM、Atmel、Cirrus Logic、Freescale、Intel、NetSilicon、 OKI、Philips、Samsung、Sharp、ST 和TI 等 .支持Analog Devices、Atmel、Freescale、OKI、Philips、ST 和TI 等厂商的ARM 处理器的Flash Loader 程序 . 软件集成了400 余个代码例程,对应于各种不同的芯片,位于...\arm\src\examples 目录下 .进一步改进了编译器速度优化,重写了的浮点运算库 .对更多嵌入式操作系统的支持 新增支持OSEK 类操作系统的OSEK Run-Time Interface (ORTI)
新增支持OSE Epsilon RTOS 的Kernel Awareness 调试 .新增支持embOS、SMX、NORTi 等的支持 .调试器的增强功能 .对堆栈运行的监测功能 .配合IAR J-Link 仿真器的新增功能 .J-Link TCP/IP 服务器 .调试器和IAR J-Link 仿真器协同配合,实现对ARM 处理器的多核调试 .对IAR J-Trace 仿真器提供全面的支持 .在C-SPY 模拟器中可执行Trace 的模拟 .支持同一芯片上多颗Flash 的Flash Loader 程序,以及通用的Flash Loader 开发指南
② EWARM 软件在芯片级支持方面的特色 .完备的各厂商ARM 处理器的C/C++和汇编语言外设寄存器定义文件 .大量适合于嵌入式代码的编程语言扩展特性,包括存储器关键字,函数,中断函数,存储器映射I/O 等 .针对评估板的例程,包含IAR、Analog Devices、Aiji System、ARM、Atmel、Cirrus Logic、 Freescale、Keil、OKI、Olimex、Pasat、Philips、Phytec、ST 和TI 等厂家的开发.支持ARM 或Thumb 模式下大至4G 字节的应用程序 .每个函数都能选择在ARM 或Thumb 模式下编译 .可生成VFP 向量浮点协处理器代码 .支持Analog Devices、Atmel、Freescale、OKI、Philips、ST 和TI 等厂商的ARM 处 器的Flash Loader 程序 . 支持ARM Angel Debug monitor
③ EWARM 编译器的软件特色 .先进的通用编译器优化和针对特定处理器的速度优化及存储器优化功能 .轻量运行库,用户可以根据需要自行配置,提供全部源代码 .灵活的存储器控制,允许详细地为代码和数据分配地址 .去除不需要的函数和变量 .C/C++变量和函数连接时全局类型检查 .可选的校验和生成功能,用于运行时映象校验 .自动将代码和数据放置到非连续的存储器区域 .强大的可重定位宏汇编器,支持丰富的命令集和操作符
④ EWARM 调试器的软件特色 . 完全集成的源代码和反汇编程序调试器 . 非常细化的执行控制(函数调用级步进) . 复杂的代码和数据断点 . 丰富的数据监视功能 . Locals,Watch,Auto,Live Watch 和Quick Watch 等变量查看窗口 . 寄存器和存储器查看窗口 . 支持STL 容器
. C/C++调用栈窗口,同时还可以显示将要进入的函数 . 双击调用链上的任何函数将更新编辑器、局部变量、寄存器、变量查看和反汇编窗口,以显示在该函数调用时的状态 . 跟踪功能,可以检查执行的历史记录。在跟踪窗口中移动时将更新编辑器和反汇编窗口以显示合适的位置。 . 控制台I/O 仿真 . 中断和I/O 模拟仿真 . 类似C 语言的宏系统,可扩充调试器的功能 . 由主机执行的应用程序系统调用仿真 . 代码覆盖率和执行时间分析工具 . 通用的Flash Loader 程序及开发指南 . 同时支持多颗Flash 的Flash Loader 程序 . 支持OSEK Run-Time Interface (ORTI) . 提供为调试器扩充第三方功能的软件开发包,如RTOS 调试扩充和仿真器驱动扩充 . 命令行调试工具
⑤ IAR C-SPY 支持的调试方法 . IAR J-Link JTAG 接口(支持所有ARM7 和ARM9 核,通过USB 或TCP/IP 连接) . RDI 接口类的第三方仿真器(Abatron BDI1000 & BDI2000, EPI Majic, Ashling Opella, Aiji OpenICE, Signum JTAGjet, ARM Multi-ICE 等) . Macraigor Wiggler, Raven, mpDemon 和USBdemon 等调试接口 . EPI Jeeni 仿真器支持 . IAR 的 ROM-Monitor . ARM 公司的Angel ROM-Monitor(用于Atmel 和Cirrus Logic 的评估板) ⑥ EWARM 图形化的集成开发环境的界面特色 . 分层次的工程组织 . 同一工作空间中允许存放多个工程 . 可停靠的窗口和多视图 . 源代码浏览 . 创建和维护库的工具 . 可以和源代码控制系统相集成
. 文本编辑器 . 支持多字节字符(汉字) . 上下文相关的帮助系统 . 根据句法着色 . 无限制的undo/redo . 搜寻、替换和增量搜寻 . Go to . 书签 . 错误标签:查阅前一个/下一个 . 自动括号配对 . 智能缩排 . 类似网页浏览器的前向/后向源码查阅 . 代码断点的设置/清除/使能/禁止 . 命令行编译连接工具
⑦ EWARM 的编程语言和标准 . 遵循ISO/ANSI C94(带有一些从C99 标准中挑选的特性)标准的C 编程语言 . 嵌入式C++扩展,支持模板、多重继承和虚拟继承、名字空间以及其它不增加执行时间或存储器开销的C++特性。完整的嵌入式C++库还包含字符串、流等特性。 . IEEE-754 浮点运算规则 . MISRA C 检查器 . 支持大量工业标准的调试和映象文件格式(如ELF/DWARF),与大多数常见的调试器和仿真器兼容 ⑧ 用户帮助 . 完备的例程和工程模板。 . 上下文相关的联机帮助系统,带有库函数查阅功能 . 印刷好的用户指南,带有详细的step-by-step 教程 . 友好、详尽和精确的错误信息和警告信息
2.3 用AXD进行代码仿真、调试 2.3.1 AXD简介 ADX(ARM extended Debugger)是ADS软件中独立于Code Warrior IDE的图形软件,可从Code Warrior for ARM Developer Suite中进入ADX进行调试,或在Windows下选择“程序”∣ARM Developer Suite v1.2∣AXD Debugger进入调试。要使用AXD必须首先有生成包含调试信息的程序,即由Code Warrior for ARM Developer Suite编译生成含有调试信息的可执行ELF格式的映像文件(*.axf)。
1 在AXD中打开调试文件 在Code Warrior for ARM Developer Suite界面中,点击Debugger进入AXD调试界面。 选择File∣Load image命令,打开Load image对话框,找到要装入的.axf映像文件,单击“打开”按钮,就可以把映像文件装载到目标内存中,如图2-22所示。 利用Exeute菜单中的子菜单项对可执行映像文件进行调试,各选项的含义如下: . 选择Go子菜单或按F5键,将全速运行代码。 . 选择Stop子菜单或按Shift+F5键,将停止运行代码。 . 选择Step In子菜单或按F8键,以单步执行代码,若遇到函数,则进入函数内执行。 . 选择Step子菜单或按F10键,以单步执行代码,若遇到函数,则把函数看成一条语句单步执行。
. 选择Step Out子菜单或按Shift+F8键,在Step In单步执行代码进入函数内后,若选该子菜单,则可以从函数中跳出返回到上一级程序执行。 . 选择Run To cursor子菜单或按F7键,以全速运行到光标处停下。 . 选择Show Execution Context子菜单,可显示执行的内容。 . 选择Delete All Breakpoint子菜单,清除所有的断点。 2.查看存储器、寄存器、变量内容
利用AXD菜单选项Processor Views和System Views中的子菜单选项可查看寄存器、变量值,还可以查看某个内存单元的数值等。各子菜单的含义如下:
选择Registers子菜单或按Ctrl+R键,可查看或修改目标板处理器中寄存器中的值 . 选择Watch子菜单或按Ctrl+E键,可对处理器设置观察点,观察点可以是寄存器、地址等, 但不能修改。特别注意:Processor Views菜单下的Watch只能观察处理器,而System Views菜单下的Watch或按Alt+E键时可对目标板上的任何资源建立观察,可增加或删除观察点。 . 选择Variables菜单或按Ctrl+E键,可查看或修改当前可执行的映像文件(程序)中的变量值,这些变量可以是局部变量、全局变量、类属变量。可增加或删除查看或修改的变量。 . 选择Memory子菜单或按Ctrl+M键,可查看或修改存储器中的值。 如在程序执行前,可以先查看两个宏变量IOPMOD和IOPDATA的当前值。方法是: . 选择AXD的Processor Views∣Memory命令或按Ctrl +M键后,查看或修改存储器中的值,如图2-23所示。
3. 在Memory Start address文本框图上,用户可以根据要查看或修改的存储器地址输入起始地址,在下面的表格中会列出连续的64个地址。因为I/O模式控制寄存器和I/O数据控制寄存器都是32位的控制寄存器,所以从0x00000000开始的连续4个地址空间存放的是I/O模式控制寄存器的值,从图中可以读出该控制寄存器的值,数据控制寄存器的内容,注意因为用的是小端模式,所以读数据时注意高地址中存放的高字节,低地址存放的是低字节。
4. 断点设置、查看 在程序调试时经常设置断点,即在程序的某处设置断点,当程序执行到断点处即可停下,这时开发人员可通过前面的方法查看寄存器、存储器或变量的值,以判定程序是否正常。设置断点的方法是将光标移到需设置断点处,使用快捷键F9在此处设置断点。 查看断点的方法是:选择System Views∣breakpoint view命令或按Alt+K键,在断点状态对话框中右击,利用快捷菜单可增加或删除断点。按F5键,程序将运行到断点,如果要进入函数内查看如何运行的,可以选择Execte∣Step Inw命令或按下F8键,进入到子函数内部进行单步程序的调试。
2.3.2 JTAG概述 JTAG是Joint Test Action Group(联合测试行动小组)的简称,由于IEEE 1149.1标准是由JTAG这个组织最初提出的,最终由IEEE批准并且标准化的。所以IEEE 1149.1这个标准一般也俗称JTAG调试标准。 JTAG标准主要用于芯片内部测试及对系统进行仿真、调试。JTAG技术是一种嵌入式调试技术,它在芯片内部封装了专门的测试电路TAP(Test Access Port测试访问口),通过专用的JTAG测试工具对内部节点进行测试。目前大多数比较复杂的器件都支持JTAG协议,如ARM、DSP、FPGA器件等。标准的JTAG接口是4线:TMS、TCK、TDI、TDO,分别为测试模式选择、测试时钟、测试数据输入和测试数据输出。JTAG测试允许多个器件通过JTAG接口串联在一起,形成一个JTAG链,能实现对多个器件分别测试。JTAG接口还常用于实现ISP(In-System Programmable在线系统可编程)功能,如对FLASH器件进行编程等。
在JTAG调试中,边界扫描(Boundary-Scan)是一个很重要的概念。边界扫描技术的基本思想是在靠近芯片的输入输出管脚上增加一个移位寄存器单元。因为这些移位寄存器单元都分布在芯片的边界上,所以被称为边界扫描寄存器(Boundary-Scan Register Cell)。 芯片处于调试状态的时候,这些边界扫描寄存器可以将芯片和外围的输入输出隔离开来。通过这些边界扫描寄存器单元,可以实现对芯片输入输出信号的观察和控制。如果需要捕获芯片某个管脚上的输出,首先需要把该管脚上的输出装载到边界扫描链的寄存器单元中去,然后通过TDO输出,这样,我们就可以从TDO上得到相应管脚上的输出信号。如果要在芯片的某个管脚上加载一个特定的信号,则首先需要通过TDI把期望的信号移位到与相应管脚相连的边界扫描链的寄存器单元里去,然后将该寄存器单元的值加载到相应的芯片管脚。
由于在正常的运行状态下,这些边界扫描寄存器对芯片来说是透明的,所以正常的运行不会受到任何影响。这样,边界扫描寄存器就提供了一个便捷的方式,用以观测和控制所需要调试的芯片。另外,芯片输入输出管脚上的边界扫描(移位)寄存器单元可以相互连接起来,在芯片的周围形成一个边界扫描链(Boundary-Scan Chain)。一般的芯片都会提供几条独立的边界扫描链,用来实现完整的测试功能。边界扫描链可以串行地输入和输出,通过相应的时钟信号和控制信号,可以方便地观察和控制处在调试状态下的芯片。 JTAG仿真器需要设备驱动程序驱动,在我们使用的教学实验系统(EDUKIT-Ⅲ),JTAG仿真器的驱动程序为两个动态链接库(EasyICEArm9Plus.dll,EasyICEArm7Plus.dll),把这两个文件拷贝到C:\EmbestIDE\Bin\Device\路径下,即可正常使用。
2.3.3 Nor和Nand Flash的区别和使用 Nor和Nand是现在市场上两种主要的非易失闪存技术。Intel公司于1988年首先开发出Nor Flash技术。这项技术的开发和投放市场彻底改变了原先由EPROM和EEPROM一统天下的局面。紧接着,1989年东芝公司发表了Nand Flash结构,强调降低每比特的成本,提供更高的性能,并且像磁盘一样可以通过接口轻松升级。在具有Nand Flash接口的系统中,Nand Flash存储器可以替代Nor Flash存储器使用。许多业内人士也搞不清楚Nand闪存技术相对于Nor技术的优越之处,因为大多数情况下闪存只是用来存储少量的代码,这时Nor闪存更适合一些。而Nand则是高数据存储密度的理想解决方案。
Nor的特点是XIP(eXecute In Place芯片内执行)特性,这样,应用程序可以直接在Flash闪存内运行,不必再把代码读到系统RAM中。Nor的传输效率很高,在1~4MB的小容量时具有很高的成本效益,但是很低的写入和擦除速度大大影响了它的性能。 Nand结构能提供极高的单元密度,可以达到高存储密度,并且写入和擦除的速度也很快。应用Nand的困难在于Flash的管理和需要特殊的系统接口。
1. 性能比较 Flash闪存是非易失存储器,可以对称作块的存储器单元块进行擦写和再编程。由于任何Flash器件的写入操作只能在空或已擦除的单元内进行,所以大多数情况下,在进行写入操作之前必须先执行擦除。Nand器件执行擦除操作是十分简单的,而Nor则要求在进行写入前先要将目标块内所有的位都写为0。 由于擦除Nor器件时是以64KB~128KB的块进行的,执行一个写入/擦除操作的时间为5s,与此相反,擦除Nand器件是以8KB~32KB的块进行的,执行相同的操作最多只需要4ms。执行擦除时块尺寸的不同进一步拉大了Nor和Nand之间的性能差距,统计表明,对于给定的一套写入操作,尤其是更新小文件时,在基于Nor的单元中进行需要更多的擦除操作。这样,当选择存储解决方案时,设计师必须权衡以下的各项因素:
. Nor的读速度比Nand稍快一些。 . Nand的写入速度比Nor快很多,Nand的4ms擦除速度远比Nor的5s快。 . 大多数写入操作需要先进行擦除操作。 . Nand的擦除单元更小,相应的擦除电路更少。 2. 容量和成本。 Nand Flash的单元尺寸几乎是Nor器件的一半,由于生产过程更为简单,Nand结构可以在给定的模具尺寸内提供更高的容量,也就相应地降低了价格。在Nand闪存中每个块的最大擦写次数是一百万次,而Nor的擦写次数是十万次。 Nor Flash占据了容量为1MB~16MB闪存市场的大部分,而Nand Flash只是用在8MB~128MB的产品当中,这也说明Nor主要应用在代码存储介质中,Nand适合于数据存储。Nand在Compact Flash、Secure Digital、PC Cards和MMC存储卡市场上所占份额最大。
3. 接口差别。 Nor Flash带有SRAM接口,有足够的地址引脚来寻址,可以很容易地存取其内部的每一个字节。基于Nor的闪存使用非常方便,可以像其他存储器那样连接,并可以在上面直接运行代码。 Nand器件使用复杂的I/O口来串行存取数据,各个产品或厂商的方法可能各不相同。8个引脚用来传送控制、地址和数据信息。Nand的读写操作采用512字节的块,这一点与硬盘管理操作类似,显然基于Nand的存储器就可以取代硬盘或其他块设备。
在使用Nand器件时,必须先写入驱动程序,才能继续执行其他操作。向Nand器件写入信息需要相当的技巧,因为设计师决不能向坏块写入,这就意味着在Nand器件上自始至终都必须进行虚拟映射。 幸运的是,S3C2410微处理器支持Nand Flash接口,大大方便了在嵌入式系统设计中的应用。鉴于两种存储器各自的优缺点,在S3C2410嵌入式系统中,对Nor Flash和Nand Flash电路都进行了设计,以方便使用。
2.3.4 烧写Flash 程序调试结束,要将其可执行文件烧写(或称固化)到目标机中Flash运行,这个过程要通过一个转门的下载软件来进行,以Embest OnLine Flash Programmer for ARM为例,来说明该软件的安装和使用。 1. 安装Flash Programmer Flash Programmer安装过程比较简单,运行Flash Programmer安装包中的Setup.exe,按照提示一步步执行即可。 Flash Programmer安装程序将自动区分电脑是否已安装Embest IDE软件的情况: ① 电脑已安装Embest IDE软件,安装程序将会把Flash Programmer缺省安装到“Embest IDE安装目录\Tools\FlashProgrammer”目录,见图2-24。同时安装程序将自动探测是否安装与IDE软件共享的设备模块和驱动程序,安装完毕后电脑无需重新启动。如果IDE已注册,软件可直接运行。
② 电脑未安装Embest IDE软件,安装程序将会把Flash Programmer缺省安装到“Program Files\ Embest\FlashProgrammer”目录,安装完毕后需要重新启动。软件正常运行时需要注册。软件安装完成后将缺省建立 Embest Tools 程序文件夹,包含执行程序和帮助的快捷方式。
2. Flash Programmer的功能 点击Flash Programmer图标,出现图2-25对话框,在第一行有四个一级菜单,下面分别介绍。 ① 文件菜单 文件菜单用于保存、打开用户设置的编程配置数据文件,该文件一般以 *.cfg形式存在。通过文件菜单,用户还可以将已打开的编程配置数据文件里另存为其他文件,以及打开最近打开过的四个编程配置文件。文件菜单各子菜单命令如表2-1所示。 表2-1 文件菜单
图2-25 Flash Programmer对话框 ② 设置菜单 设置菜单仅包含Configure子菜单。功能见表2-2 表2-2 设置菜单
选择Setting > Configure…子菜单,将弹出编程设备配置对话框,如图2-26所示:
连接设备(Remote Device),该下拉框中显示所有本软件支持的编程设备,用户可以选择其中一种,下拉框下方将显示对应该设备的说明和版本。 通讯类型(Communication type),设置该设备与主机使用的连接方式和连接到的主机通讯口。 通讯口(Parallel Port),按实际连接设置。 ③ Tools 菜单 Tools 菜单设置菜单仅包含Option…子菜单,功能见2-3。 表2-3 Tools 菜单 选择Tools > Option…子菜单,将弹出应用选项对话框,见图2-27
输出信息记录文件(Output information to log file),选择该检查框则应用程序将所有输出的提示信息和错误信息记录到安装目录下的 Info.log文件。 编程时载入扇区所有数据(Loading all sector data when programming),部分Flash芯片编程时需要一次性载入扇区全部数据,则用户可以选择本选项完成编程操作。 超时(Time Out),设置超时时间,单位为秒。 测试RAM区大小(Test Ram Size),设置目标测试(Target Test)时测试的RAM存储区大小,单位为Kbyte;根据本软件运行时需要,一般情况下应设置为4K,对于必须一次性载入一个扇区数据的Flash芯片,应该设置为 4K+扇区大小。
执行FLASH操作前复位次数(Reset Count Before Flash Command),设置执行编程、擦除、保护等命令前复位芯片的次数。 ④ Help 菜单 Help 菜单该菜单最重要的是Contents子菜单,内部有我们需要的许多资料,特别是用户手册,对我们正确使用Flash Programmer有很大帮助。帮助菜单项见表2-4:
3. Flash Programmer的使用 Net Start评估板是一款基于SAMSUNG公司ARM7芯片S3C4510的评估电路板,板上包含2M字节的Flash芯片,型号是AMD公司AM29LV160DB,以及16M字节的SDRAM,板上应用程序为ucLinux,是目前比较流行的一款评估板。我们以Net Start为例来说明Flash Programmer的使用。 Net Start评估板使用FLASH前64K存储空间,即1到4号扇区保存BootLoader软件,该软件用于启动固化在5到35号扇区的ucLinux,以及烧写5到35号扇区内容。本节讲述如何使用Flash Programmer对Net Start评估板Flash进行编程,用户可以参照本实例对其他电路板进行编程配置。
编程设备设置 选择Setting > Configure…子菜单,弹出编程设备配置对话框,如图2-28所示: 选择合适的编程设备并设置通讯类型和通讯通道。 ② 处理器设置 选择处理器CPU子对话框,如图2-29所示:
选择SAMSUNG公司S3C4510处理器,选择小端模式,按表2-5设置以下寄存器:
FLASH芯片设置 选择FLASH子对话框,如图2-30所示: 图2-30 FLASH对话框
设置RAM起始地址为0,选择需要编程的BIN格式文件,如果需要上载,选择上载文件。 选择AMD公司AM29LV160B/DB芯片,选择访问宽度为16位,选择芯片数目为1片,设置Flash起始地址为为0x180000,如果要烧写BootLoader程序,选择扇区范围为1到4,如果要烧写ucLinux,选择扇区范围为5到35。 编程数据设置 选择编程子对话框,如图2-31所示: 设置RAM起始地址为0,选择需要编程的BIN格式文件,如果需要上载,选择上载文件。 图2-31 编程数据设置
5 目标板测试 选择处理器CPU子对话框,点击目标板测试Target Test按钮,开始目标测试,测试时弹出以下对话框图2-31,通知SYSCFG寄存器写入值和读取值不相同,原因是SYSCFG寄存器中包含S3C4510器件标识,因此选择YES继续测试。弹出类似的对话框均选择YES继续测试。 图2-32目标板测试对话框 RAM区测试完后,开始获取Flash设备标识号,如果获取的Flash标识和保存的标识相同,表示测试成功,输出信息如下图: 图2-33表示测试成功对话框
6 FLASH编程 用户可以点击编程按钮进行编程操作或其他Flash操作。 2.3.5 程序的运行 程序固化到FLASH中后,运行前往往将其复制到SDRAM中去,这样可以提高运行速度,作者在科研工作中,因工作需要,编写了一段将程序从FLASH中复制到DSRAM中去的C语言程序,可供参考,其中ARM9init(void)程序略。
//------------------------------------------------------------------------------ // 主程序 #include "def.h" #include "2410addr.h" #include "2410lib.h" #define ARM_ADDR 0X30000000;// 定义SDRAM地址 void (*run)(void ); //定义函数指针 void ARM9init(void); void CopyFromFlashToRAM(U32 * FlashAddr,U32 *ArmAddr,U32 ul); void copy(void); void main(void) { run=(void(*)(void)) ARM_ADDR; ARM9init(); copy(); run(); }
//---------------------------------------------------------------------------- // 复制程序 CopyFromFlashToRAM(U32 * pulFlashAddr,U32 *pulArmAddr,U32 ul) { U32 *pulSource=pulFlashAddr; U32 *pulDest=pulArmAddr; U32 i; ul/=4; for(i=0;i<ul;i++) *pulDest++=*pulSource++; }
//----------------------------------------------------------------------------- // 调复制程序 copy(void) { U32*p1; U32*p2; P1=(U32 * )0x00200000; P2=(U32 * )0x30000000; CopyFromFlashToRAM(p1,p2,0x20000); }
2.4 ARM C语言程序的基本规则和系统初始化程序 在应用系统的程序设计中,若所有的编程任务均由汇编语言来完成,其工作量巨大,并且不易移植。由于ARM的程序执行速度较高,存储器的存储速度和存储量也很高,因此,C语言的特点充分发挥,使得应用程序的开发时间大为缩短,代码的移植十分方便,程序的重复使用率提高,程序架构清晰易懂,管理较为容易等等。因此,C语言的在ARM编程中具有重要地位。 在ARM程序的开发中,需要大量读写硬件寄存器,尽量缩短程序的执行时间,因此部分初始化代码一般使用汇编语言来编写,比如ARM的启动代码,ARM的操作系统的移植代码等,除此之外,绝大多数代码可以使用C语言来完成。 C语言使用的是标准的C语言,ARM的开发环境实际上就是嵌入了一个C语言的集成开发环境,只不过这个开发环境和ARM的硬件紧密相关。
在使用C语言时,有时要用到和汇编语言的混合编程。当汇编代码较为简洁,则可使用直接内嵌汇编的方法,否则,将汇编程序以文件的形式加入项目当中,通过ATPCS(ARM/Thumb Procedure Call Standard)的规定与C程序相互调用与访问。 ATPCS,就是ARM、Thumb的过程调用标准,它规定了一些子程序间调用的基本规则。如寄存器的使用规则,堆栈的使用规则,参数的传递规则等。 在C程序和ARM的汇编程序之间相互调用必须遵守ATPCS。而使用ADS的C语言编译器编译的C语言子程序满足用户指定的ATPCS的规则。但是,对于汇编语言来说,完全要依赖用户保证各个子程序遵循ATPCS的规则。具体来说,汇编语言的子程序应满足下面3个条件:
. 在子程序编写时,必须遵守相应的ATPCS规则; 基本的ATPCS规定,详情请见相关PDF文档,简单说明就是: 1. 汇编程序调用C程序 . 汇编程序的设置要遵循ATPCS规则,保证程序调用时参数正确传递。 . 在汇编程序中使用IMPORT伪指令声明将要调用的C程序函数。 . 在调用C程序时,要正确设置入口参数,然后使用BL调用。
2. C程序调用汇编程序 . 汇编程序的设置要遵循ATPCS规则,保证程序调用时参数正确传递。 . 在汇编程序中使用EXPORT伪指令声明本子程序,使其他程序可以调用此子程序。 . 在C语言中使用extern关键字声明外部函数(声明要调用的汇编子程序)。 在C语言的环境内开发应用程序,一般需要一个汇编的启动程序,从汇编的启动程序,跳到C语言下的主程序,然后,执行C程序,在C环境下读写硬件的寄存器,一般是通过宏调用,在每个项目文件的Startup2410/INC目录下都有一个2410addr.h的头文件,那里面定义了所有关于2410的硬件寄存器的宏,对宏读写,就能操作2410的硬件,具体的编程规则同标准C语言。
2.4.2 初始化程序和开发环境设置 基于ARM芯片的应用系统,多数为复杂的片上系统,在系统中,多数硬件模块都是可配置的,需要由软件来预先设置其需要的工作状态,因此在用户的应用程序之前,需要由专门的一段代码来完成对系统基本的初始化工作。由于此类代码直接面对处理器内核和硬件控制器进行编程,故一般均用汇编语言实现。系统的基本初始化内容一般包括: . 分配中断向量表 . 初始化存储器系统 . 初始化各工作模式的堆栈
. 初始化有特殊要求的硬件模块 . 初始化用户程序的执行环境 . 切换处理器的工作模式 此外,还要对项目的交叉编译环境进行设置,这其中包括处理器设置、仿真器设置和调试设置等20几个大项、近100个小项。 系统的初始化程序和交叉编译环境设置是初次学习ARM程序设计最难掌握的内容之一,初次学习ARM程序设计,有哪些硬件模块需要预先设置其需要的工作状态,如何设置?初始化程序代码直接面对处理器内核和硬件控制器进行编程,故一般均用汇编语言实现,初学者对ARM的汇编语言不熟;交叉编译环境设置大约有20几个大项,近100个小项要设置,如何保证各项都设置的正确,这些都是我们需要解决的问题。
最简单的做法是我们打开一个和我们开发的项目相近的系统提供的例子项目,在例子项目中,系统的初始化程序和交叉编译环境都是设置好的,我们可先不去修改,而是先保留,我们只是把其中的主程序内容换成我们新项目内容,把我们项目所需函数加入进去,这样,我们就绕过了系统初始化程序和交叉编译环境设置的困惑,节省系统开发时间。 比如,我们要开发一个LCD显示项目,项目的初始化程序可能很难,简单作法是我们打开一个例子项目lcd.mcp,如图2-33所示,在项目窗口我们看到,初始化程序在一个文件夹组startup2410中,在其中包括3个汇编语言程序2410INIT.S、OPTION.S和2410SLIB.S,2个C语言程序2410LIB.C和TARGET.C,五个C语言头文件2410addr.h、2410lib.h、2410slib.h、和option.h,很复杂。
现在我们先不去研究这些程序,把startup2410文件夹保留,只修改Application文件夹中的MAIN 现在我们先不去研究这些程序,把startup2410文件夹保留,只修改Application文件夹中的MAIN.C,把我们项目所需要函数加到其中一个文件夹或新建一个文件夹加到项目中,可以很快完成嵌入式系统开发。
图2-33 lcd.mcp的项目窗口
第二章习题与练习 1,在你的计算机中安装ADS1.2,并建立一个新项目。 2,如何简化系统初始化程序和开发环境设置,快速完成嵌入式控制系统设计? 3,编写一个C语言程序,将用户程序从FLASH复制到SDRAM,并从SDRAM中运行。 4,Nor和Nand Flash的区别和使用有哪写不同? 5,大致描述Flash Programmer软件的安装和使用。 6,参考图2-23,分析lcd.mcp项目包括几个文件夹,哪个文件夹包含系统初始化程序? 7,系统初始化应完成哪些工作?
第三章 ARM9芯片S3C2410片上资源 3.1 S3C2410处理器介绍 S3C2410微处理器是一款由Samsung公司为手持设备设计的低功耗、高度集成的基于ARM920T核的微处理器。为了降低系统总成本和减少外围器件,这款芯片中还集成了下列部件:16KB指令Cache、16KB数据Cache、MMU、外部存储器控制器、LCD控制器(STN和TFT)、NAND Flash控制器、4个DMA通道、3个UART通道、1个I2C总线控制器、1个I2S总线控制器,以及4个PWM定时器和一个内部定时器、通用I/O口、实时时钟、8通道10位ADC和触摸屏接口、USB主、USB从、SD/MMC卡接口等。现在它广泛应用于PDA(Personal Digital Assistant,个人数码助理,一般指掌上电脑)、移动通讯、路由器、工业控制等领域,其内部结构如图3-1。 为了提高系统运行速度,减少能量损失,ARM920T核微处理器把片上器件按器件工作频率,使用频度分成三个模块,各个模块通过各自总线连接,模块之间采用一种叫总线桥的结构过度。下面简单介绍一下各总线特点。
3.1.1 AMBA、AHB、APB 总线特点 随着深亚微米工艺技术日益成熟,集成电路芯片的规模越来越大。数字IC从基于时序驱动的设计方法,发展到基于IP复用的设计方法,并在片上系统(SoS )设计中得到了广泛应用。在基于IP复用的SoC设计中,片上总线设计是最关键的问题。为此,业界出现了很多片上总线标准。其中,由ARM公司推出的AMBA片上总线受到了广大IP开发商和SoC系统集成者的青睐,已成为一种流行的标准片上结构。AMBA规范主要包括AHB(Advanced High performance Bus)系统总线和APB(Advanced Peripheral Bus)外围总线。 AMBA 2.0规范包括四个部分:AHB、ASB、APB和Test Methodology。AHB的相互连接采用了传统的带有主模块和从模块的共享总线,接口与互连功能分离,这对芯片上模块之间的互连具有重要意义。AMBA已不仅是一种总线,更是一种带有接口模块的互连体系。下面将简要介绍比较重要的AHB和APB总线。
大多数挂在总线上的模块(包括处理器)只是单一属性的功能模块:主模块或者从模块。主模块是向从模块发出读写操作的模块,如CPU,DSP等;从模块是接受命令并做出反应的模块,如片上的RAM,AHB/APB 桥等。另外,还有一些模块同时具有两种属性,例如直接存储器存取模块(DMA)在编程时是从模块,但在系统传输数据时必须是主模块。 如果总线上存在多个主模块,就需要仲裁器来决定如何控制各种主模块对总线的访问。虽然仲裁规范是AMBA总线规范中的一部分,但具体使用的算法由RTL设计工程师决定,其中两个最常用的算法是固定优先级算法和循环制算法。
AHB总线上最多可以有16个主模块和任意多个从模块,如果主模块数目大于16,则需再加一层结构(具体参阅ARM公司推出的Multi-layer AHB规范)。APB 桥既是APB总线上唯一的主模块,也是AHB系统总线上的从模块。其主要功能是锁存来自AHB系统总线的地址、数据和控制信号,并提供二级译码以产生APB外围设备的选择信号,从而实现AHB协议到APB协议的转换。 AHB主要用于高性能模块(如CPU、DMA和DSP等)之间的连接,作为SoC的片上系统总线,它包括以下一些特性:单个时钟边沿操作;非三态的实现方式;支持突发传输;支持分段传输;支持多个主控制器;可配置32位~128位总线宽度;支持字节、半字节和字的传输。 APB主要用于低带宽的周边外设之间的连接,例如UART等,它的总线架构不像AHB支持多个主模块,在APB里面唯一的主模块就是APB 桥。其特性包括:两个时钟周期传输;无需等待周期和回应信号;控制逻辑简单,只有四个控制信号。
图3-1 S3C2410结构框图
3.1.2 S3C2410处理器体系结构 . ARM920T核,16位/32位RISC(精简指令系统)结构和ARM精简指令集; . ARM MMU,支持Windows CE, Linux等操作系统; . 指令Cache、数据Cache、写缓冲; . 支持ARM调试结构,片上ICE支持JTAG调试方式; . 内置先进微控制器总线接口(AMBA)。 3.1.3 S3C2410处理器管理系统 . 支持大端(Big Endian)/小端(Little Endian)模式; . 地址空间为每个内存块128MB(一共1GB),每个内存块支持8/16/32位数据总线编程; . 8个内存块,6个用于ROM、SRAM和其它,2个用于ROM/SRAM/SDRAM; . 1个起始地址和大小可编程的内存块 (Bank7); . 7个起始地址固定的内存块(Bank0~Bank6); . 所有内存块可编程寻址周期; . 支持SDRAM自动刷新模式; . 支持多种类型ROM启动,包括NOR/NAND Flash、EEPROM等。
3.1.4 S3C2410处理器存储器映射 3.1.5 S3C2410处理器时钟和电源管理 S3C2410的存储空间映射如图3-2所示: 1.时钟 S3C2410的主时钟由外部晶振或者外部时钟提供,选择后可以产生3种时钟信号,分别是CPU使用的FCLK、AHB总线使用的HCLK和APB总线使用的FCKL。时钟管理模块同时拥有两个锁相环,一个称为MPLL,拥于FCLK、HCLK和PCLK;另一个称为UPLL, 用于USB设备。 时钟源选择 对时钟的选择是通过S3C2410引脚上OM[3:2]实现的,JU具体如表3-1所示。
表3-1 时钟源选择 S3C2410引脚的OM[3:2]=00时,晶体为MPLL CLK和UPLL CLK提供时钟源;OM[3:2]=01时,晶体为MPLL CLK提供时钟源,EXTCLK为UPLL CLK提供时钟源;OM[3:2]=10时,EXTCLK为MPLL CLK提供时钟源,晶体为UPLL CLK提供时钟源;OM[3:2]=11时,EXTCLK为MPLL CLK和UPLL CLK提供时钟。
3. 时钟控制逻辑 时钟控制逻辑决定了所使用的时钟源,是采用MPLL作为FCLK,还是采用外部时钟。复位后,即使不想改变默认的PLLCON值,也需要重新写一遍。FCLK由ARM920T核使用,HCLK提供给AHB总线,PCLK提供给了APB总线。S3C2410支持HCLK、FCLK和PCLK的分频选择,其比率是通过CLKDIV寄存器中的HDIVN和PDIVN控制的,如表3-2所示。
表3-2 分频设定表 4. 电源管理 S3C2410电源管理模块通过4种模式有效地控制功耗,即正常(Normal)模式、省电(Slow)模式、空闲(Idle)模式和断电(Power-off)模式。 • Normal模式:为CPU和所有的外设提供时钟,所有的外设开启,该模式下的功耗最大。这种模式允许用户通过软件控制外设,可以断开提供给外设的时钟以降低功耗。 • Slow模式:采用外部时钟生产FCLK的方式,此时电源的功耗取决于外部时钟。 • Idle模式:断开FCLK与CPU核的连接,外设保持正常,该模式下的任何中断都可唤醒CPU。
• Power-off模式:断开内部电源,只给内部的唤醒逻辑供电。一般模式下需要两个电源,一个提供给唤醒逻辑,另外一个提供给CPU和内部逻辑,在Power-off模式下,后一个电源关闭。该模式可以通过EINT[15:0]和RTC唤醒。 5. 时钟和电源管理寄存器 S3C2410通过控制寄存器实现对时钟和电源的管理,相关寄存器如表3-3所示 表3-3 时钟控制器
3.2 S3C2410处理器片上资源的定义和使用 在MCS-51单片机开发系统中,所有的系统资源都在reg51.h头文件中予以定义,我们在编程时将reg51.h头文件引入我们的程序,在程序中就可以很方便的使用这些系统资源。 和开发MCS-51单片机一样,S3C2410在头文件2410addr.h中,将S3C2410的所有系统资源都进行了定义,我们在编写S3C2410的驱动程序时必需引用这个头文件。 2410addr.h将系统所有的资源进行了宏定义,宏的名称就是所定义的寄存器的名字前面加一个小写的“r”,方便记忆。 2410addr.h内容包括:Memory control、USB Host、INTERRUPT、DMA、CLOCK & POWER MANAGEMENT、LCD CONTROLLER、NAND flash、UART、PWM TIMER、USB DEVICE、WATCH DOG TIMER、IIC、IIS、I/O PORT、RTC、ADC、SPI、ISR、 SD Interface、PENDING BIT等,近20类。如Memory control、I/O PORT、LCD CONTROLLER、NAND flash寄存储器的宏定义如下:
// Memory control #define rBWSCON (*(volatile unsigned *)0x48000000) //Bus width & wait status #define rBANKCON0 (*(volatile unsigned *)0x48000004) //Boot ROM control #define rBANKCON1 (*(volatile unsigned *)0x48000008) //BANK1 control #define rBANKCON2 (*(volatile unsigned *)0x4800000c) //BANK2 cControl #define rBANKCON3 (*(volatile unsigned *)0x48000010) //BANK3 control #define rBANKCON4 (*(volatile unsigned *)0x48000014) //BANK4 control #define rBANKCON5 (*(volatile unsigned *)0x48000018) //BANK5 control #define rBANKCON6 (*(volatile unsigned *)0x4800001c) //BANK6 control
#define rBANKCON7 (*(volatile unsigned *)0x48000020) //BANK7 control #define rREFRESH (*(volatile unsigned *)0x48000024) //DRAM/SDRAM refresh #define rBANKSIZE (*(volatile unsigned *)0x48000028) //Flexible Bank Size #define rMRSRB6 (*(volatile unsigned *)0x4800002c) //Mode register set for SDRAM #define rMRSRB7 (*(volatile unsigned *)0x48000030) //Mode register set for SDRAM //I/O PORT #define rGPACON (*(volatile unsigned *)0x56000000) //Port A control
#define rGPADAT (*(volatile unsigned *)0x56000004) //Port A data #define rGPBCON (*(volatile unsigned *)0x56000010) //Port B control #define rGPBDAT (*(volatile unsigned *)0x56000014) //Port B data #define rGPBUP (*(volatile unsigned *)0x56000018) //Pull-up control B #define rGPCCON (*(volatile unsigned *)0x56000020) //Port C control #define rGPCDAT (*(volatile unsigned *)0x56000024) //Port C data #define rGPCUP (*(volatile unsigned *)0x56000028) //Pull-up control C #define rGPDCON (*(volatile unsigned *)0x56000030) //Port D control #define rGPDDAT (*(volatile unsigned *)0x56000034) //Port D data
#define rGPDUP (*(volatile unsigned *)0x56000038) //Pull-up control D #define rGPECON (*(volatile unsigned *)0x56000040) //Port E control #define rGPEDAT (*(volatile unsigned *)0x56000044) //Port E data #define rGPEUP (*(volatile unsigned *)0x56000048) //Pull-up control E #define rGPFCON (*(volatile unsigned *)0x56000050) //Port F control #define rGPFDAT (*(volatile unsigned *)0x56000054) //Port F data #define rGPFUP (*(volatile unsigned *)0x56000058) //Pull-up control F #define rGPGCON (*(volatile unsigned *)0x56000060) //Port G control
#define rGPGDAT (*(volatile unsigned *)0x56000064) //Port G data #define rGPGUP (*(volatile unsigned *)0x56000068) //Pull-up control G #define rGPHCON (*(volatile unsigned *)0x56000070) //Port H control #define rGPHDAT (*(volatile unsigned *)0x56000074) //Port H data #define rGPHUP (*(volatile unsigned *)0x56000078) //Pull-up control H // LCD CONTROLLER #define rLCDCON1 (*(volatile unsigned *)0x4d000000) //LCD control 1 #define rLCDCON2 (*(volatile unsigned *)0x4d000004) //LCD control 2 #define rLCDCON3 (*(volatile unsigned *)0x4d000008) //LCD control 3 #define rLCDCON4 (*(volatile unsigned *)0x4d00000c) //LCD control 4
#define rLCDCON5 (*(volatile unsigned *)0x4d000010) //LCD control 5 #define rLCDSADDR1 (*(volatile unsigned *)0x4d000014) //Frame buffer start address 1 #define rLCDSADDR2 (*(volatile unsigned *)0x4d000018) //Frame buffer start address 2 #define rLCDSADDR3 (*(volatile unsigned *)0x4d00001c) //Virtual screen address set #define rREDLUT (*(volatile unsigned *)0x4d000020) //STN Red lookup table #define rGREENLUT (*(volatile unsigned *)0x4d000024) //STN Green lookup table #define rBLUELUT (*(volatile unsigned *)0x4d000028) //STN Blue lookup table #define rDITHMODE (*(volatile unsigned *)0x4d00004c) //STN Dithering mode
#define rTPAL (. (volatile unsigned #define rTPAL (*(volatile unsigned *)0x4d000050) //TFT Temporary palette #define rLCDINTPND (*(volatile unsigned *)0x4d000054) //LCD Interrupt pending #define rLCDSRCPND (*(volatile unsigned *)0x4d000058) //LCD Interrupt source #define rLCDINTMSK (*(volatile unsigned *)0x4d00005c) //LCD Interrupt mask #define rLPCSEL (*(volatile unsigned *)0x4d000060) //LPC3600 Control #define PALETTE 0x4d000400 //Palette start address // NAND flash #define rNFCONF (*(volatile unsigned *)0x4e000000) //NAND Flash configuration
#define rNFCMD (*(volatile U8 *)0x4e000004) //NADD Flash command #define rNFADDR (*(volatile U8 *)0x4e000008) //NAND Flash address #define rNFDATA (*(volatile U8 *)0x4e00000c) //NAND Flash data #define rNFSTAT (*(volatile unsigned *)0x4e000010) //NAND Flash operation status #define rNFECC (*(volatile unsigned *)0x4e000014) //NAND Flash ECC #define rNFECC0 (*(volatile U8 *)0x4e000014) #define rNFECC1 (*(volatile U8 *)0x4e000015) #define rNFECC2 (*(volatile U8 *)0x4e000016)
在我们开发的程序中,引用2410addr.h头文件以后,就可以使用这些宏定义来对这些寄存器进行操作,这些寄存器的用法下面陆续介绍。更详细内容可参见随书提供软件包,参考程序24120TEST中的2410addr.h,(在人民邮电出版社网站http://www.ptpress.com.cn免费下载)。 3.3 编程参考软件包2410TEST 在厂家提供的资料中,有一个2410TEST软件包,里面包括几乎所有S3C2410硬件驱动的C语言例子和头文件,仔细阅读这些程序对我们编程有很大帮助。2410TEST软件包在随书提供软件包中,可在人民邮电出版社网站http://www.ptpress.com.cn免费下载。 在软件包中有一个2410test.c程序,是一个实验S3C2410各项功能程序,主要部分列出如下,并做必要解释:
//------------------------------------------------------------------------ // 引入实验所需头文件 #include <stdlib.h> #include <string.h> #include "def.h" #include "option.h" #include "2410addr.h" #include "2410lib.h" #include "2410slib.h"
#include "2410etc.h" #include "2410IIC.h" #include "2410iis.h" #include "2410int.h" #include "2410RTC.h" #include "2410swi.h" #include "timer.h" #include "adc.h" #include "dma.h" #include "dma2.h" #include "eint.h" #include "extdma.h" #include "k9s1208.h" #include "mmu.h" #include "nwait.h" #include "sdi.h" #include "stone.h"
#include "ts_auto.h" #include "ts_sep.h" #include "usbfifo.h" #include "IrDA.h" #include "lcd.h" #include "lcdlib.h" #include "glib.h" #include "palette.h" #include "spi.h" #include "uart0.h" #include "uart1.h" #include "uart2.h" #include "etc.h" #include "flash.h" #include "idle.h" #include "pd6710.h" #include "pll.h"
#include "power.h" #include "pwr_c.h" #include "stop.h" //--------------------------------------------------------------------------- // 定义一个二维的函数指针数组,数组中第一列是函数指针,第二列是函数功能提示 void * function[][2]= { //ADC, TSP (void *)Test_Adc, "ADC ", (void *)Test_DMA_Adc, "ADC with DMA ", (void *)Ts_Sep, "ADC TSP Seperate ", (void *)Ts_Auto, "ADC TSP Auto ", //DMA (void *)Test_DMA, "DMA M2M ", (void *)Test_DMAWorst, "DMA Worst Test ", (void *)Test_Dma0Xdreq, "External DMA ",
//EINT (void *)Test_Eint, "External Interrupt ", //IIC (void *)Test_Iic, "IIC(KS24C080)INT ", (void *)Test_Iic2, "IIC(KS24C080)POL ", //IIS (void *)Record_Iis, "Reco IIS UDA1341 ", (void *)Test_Iis, "Play IIS UDA1341 ", //Interrupt (void *)Test_Fiq, "FIQ Interrupt ", (void *)Change_IntPriorities, "Change INT Priority ", //IrDA (void *)Test_IrDA_Rx, "UART2 IrDA Rx ", (void *)Test_IrDA_Tx, "UART2 IrDA Tx
//LCD (void *)Test_Lcd_Stn_1Bit, "STN 1Bit ", (void *)Test_Lcd_Stn_2Bit, "STN 2Bit ", (void *)Test_Lcd_Stn_4Bit, "STN 4Bit ", (void *)Test_Lcd_Cstn_8Bit, "CSTN 8Bit ", (void *)Test_Lcd_Cstn_8Bit_On, "CSTN 8Bit On ", (void *)Test_Lcd_Cstn_12Bit, "CSTN 12Bit ", (void *)Test_Lcd_Tft_8Bit_240320, "TFT240320 8Bit ", (void *)Test_Lcd_Tft_8Bit_240320_On, "TFT240320 8Bit On ", (void *)Test_Lcd_Tft_16Bit_240320, "TFT240320 16Bit ", (void *)Test_Lcd_Tft_1Bit_640480, "TFT640480 1Bit ", (void *)Test_Lcd_Tft_8Bit_640480, "TFT640480 8Bit ", (void *)Test_Lcd_Tft_16Bit_640480, "TFT640480 16Bit ", (void *)Test_Lcd_Tft_8Bit_640480_Bswp, "TFT640480 BSWP ", (void *)Test_Lcd_Tft_8Bit_640480_Palette, "TFT640480 Palette ", (void *)Test_Lcd_Tft_16Bit_640480_Hwswp,"TFT640480 HWSWP ",
//Memory //MPLL (void *)Test_PLL, "MPLL Change ", (void *)ChangePLL, "MPLL MPS Change ", (void *)Test_PllOnOff, "MPLL On/Off ", //PMS (void *)Test_SlowMode, "PMS Slow ", (void *)Test_HoldMode, "PMS Hold ", (void *)Test_IdleMode, "PMS Idle ", (void *)Test_MMUIdleMode, "PMS Idle(MMU) ", (void *)Test_IdleModeHard, "PMS Idle Hard ", (void *)Test_InitSDRAM, "PMS SDRAM Init ", (void *)Test_StopMode, "PMS STOP ", (void *)Test_PowerOffMode, "PMS Power-Off STOP ", (void *)Test_PowerOffMode_100Hz, "PMS Power-Off 100Hz ", (void *)MeasurePowerConsumption, "PMS Measure Power ",
//RTC (void *)Test_Rtc_Alarm, "RTC Alarm ", (void *)Display_Rtc, "RTC Display ", (void *)RndRst_Rtc, "RTC Round Reset ", (void *)Test_Rtc_Tick, "RTC Tick ", //SDI (void *)Test_SDI, "SDI Write/Read ", //SPI (void*) Test_Spi_MS_int, "SPI0 RxTx Int ", (void *)Test_Spi_MS_poll, "SPI0 RxTx POLL ", (void *)Test_Spi_M_Tx_DMA1, "SPI0 Master Tx DMA1 ", (void *)Test_Spi_S_Rx_DMA1, "SPI0 Slave Rx DMA1 ", (void *)Test_Spi_M_Rx_DMA1, "SPI0 Master Rx DMA1 ", (void *)Test_Spi_S_Tx_DMA1, "SPI0 Slave Tx DMA1 ", (void *)Test_Spi_M_Int, "SPI0 Master RxTx INT", (void *)Test_Spi_S_Int, "SPI0 Slave RxTx INT ",
//Timer (void *)Test_TimerInt, "Timer Interrupt ", (void *)Test_Timer, "Timer Tout ", //UART (void *)Test_Uart0_Int, "UART0 Rx/Tx Int ", (void *)Test_Uart0_Dma, "UART0 Rx/Tx DMA ", (void *)Test_Uart0_Fifo, "UART0 Rx/Tx FIFO ", (void *)Test_Uart0_AfcTx, "UART0 AFC Tx ", (void *)Test_Uart0_AfcRx, "UART0 AFC Rx ", (void *)Test_Uart1_Int, "UART1 Rx/Tx Int ", (void *)Test_Uart1_Dma, "UART1 Rx/Tx DMA ", (void *)Test_Uart1_Fifo, "UART1 Rx/Tx FIFO ", (void *)Test_Uart1_AfcTx, "UART1 AFC Tx ", (void *)Test_Uart1_AfcRx, "UART1 AFC Rx ", (void *)Test_Uart2_Int, "UART2 Rx/Tx Int ", (void *)Test_Uart2_Dma, "UART2 Rx/Tx DMA ", (void *)Test_Uart2_Fifo, "UART2 Rx/Tx FIFO ",
//USB (void *)Test_USBFIFO, "USB FIFO Test ", //WDT (void *)Test_WDT_IntReq, "WDT INT Request ", //ETC (void *)Test_XBREQ, "External Bus Reqest ", (void *)Test_NonalignedAccess, "NonAlgined Access ", (void *)Test_PD6710, "PC Card (PD6710) ", (void *)ReadPageMode, "Read Page Mode ", (void *)Test_SwiIrq, "SWI ", (void *)Test_WaitPin, "External Wait ", (void *)Test_ISram, "Stone Test ", (void *)Test_NecInterrupt, "ETC NEC Int ", (void *)Test_BattFaultInterrupt, "nBATT_FAULT int ", //NAND, NOR Flash (void *)K9S1208_PrintBadBlockNum, "NAND View Bad Block ",
(void *)K9S1208_PrintBlock, "NAND View Page ", (void *)K9S1208_Program, "NAND Write ", (void *)TestECC, "NAND ECC ", (void *)ProgramFlash, "NOR Flash Program ", 0,0 }; //------------------------------------------------------------------------------- // 主程序 void Main(void) { int i; MMU_Init(); //内存管理初始化 ChangeClockDivider(1,1);// 定义FCLK、HCLK,PCLK比例 //1:2:4 ChangeMPllValue(0xa1,0x3,0x1); // FCLK=202.8MHz Port_Init(); //I/O口初始化
Uart_Printf("%2d:%s",i,function[i][1]); if((int)(function[i][0])==0) //显示结束跳出 { Uart_Printf("\n"); break; } if((i%4)==0) Uart_Printf("\n"); //每行显示4项 Uart_Printf("\nSelect the function to test : ");//提示:选择某项实验 i = Uart_GetIntNum(); //读实验项目号放i中 //GPG4 Output Port [9:8] 01 G口初始化,开LCD显示 rGPGCON = (rGPGCON & 0xfffffcff) | (1<<8); rGPGDAT = (rGPGDAT & 0xffef) | (1<<4);
if(i>=0 && (i<(sizeof(function)/8)) ) ( (void ( if(i>=0 && (i<(sizeof(function)/8)) ) ( (void (*)(void)) (function[i][0]) )();//如果i在实验范围内,做第i项实验 } } 2410test.c程序提供了S3C2410所有硬件资源的驱动例子,根据我们系统的需要,再参考具体函数,对我们编程会有很大帮助。
第三章习题与练习 1,从人民邮电出版社网站http://www.ptpress.com.cn下载随书提供软件包,打开2410addr.h头文件,仔细阅读程序,熟悉程序。 2,从人民邮电出版社网站http://www.ptpress.com.cn下载随书提供软件包,打开2410TEST文件,熟悉程序UART0.C和UART0.H,练习串口编程和I/O口操作,熟悉中断程序编制。 3, 从人民邮电出版社网站http://www.ptpress.com.cn下载随书提供软件包,打开2410TEST文件,熟悉练习串口编程和I/O口操作。 4,void * function[][2]定义的是一个什么类型的二维数组,数组中每个元素代表什么变量? 5,2410addr.h将系统所有的资源进行了宏定义,宏的名字有什么特点?
6,S3C2410电源管理模块通过几种模式有效地控制功耗? 7,S3C2410处理器体系结构中有几个存储器模块,每个Bank的大小是多少?总的Bank大小是多少?
第四章 S3C2410的中断系统 4.1 S3C2410的处理器中断 S3C2410的中断控制逻辑如图4-1所示,S3C2410可以处理多达56个中断源的中断请求。这些中断源可以是来自片内外设的的中断,比如DMA、UART和I2C等;也可以来自处理器的外部中断输入引脚。在这些中断源中,有如下11个中断源通过分支中断控制器来申请使用中断。 INT_ADC A/D转换中断; INT_TC 触摸屏中断; INT_ERR2 UART2收发错误中断; INT_TXD2 UART2发送中断; INT_RXD2 UART2接收中断; INT_ERR1 UART1收发错误中断; INT_TXD1 UART1发送中断;
INT_RXD1 UART1接收中断; INT_ERR0 UART0收发错误中断; INT_TXD0 UART0发送中断; INT_RXD0 UART0接收中断。 片内外设UARTn中断和外部中断输入EINTn是逻辑“或”的关系,它们共用一根中断请求线。 中断控制逻辑(interrupt controller logic)的任务是在片内外围和外部中断源组成的多重中断发生时,选择其中一个中断,通过FIQ (快速中断请求)或IRQ(通用中断请求)向CPU内核发出中断请求。 图4-1 S3C2410 的中断逻辑
实际上最初CPU内核只有FIQ和IRQ两种中断,其他中断都是各个芯片厂家在设计芯片时,通过加入一个中断控制器来扩展定义的。这些中断根据中断优先级的高低来进行处理,更符合实际应用系统中要求提供多个中断源的要求。例如,如果定义所有的中断源为IRQ中断(通过中断模式寄存器设置),并且同时有10个中断发出请求,那么这时可以通过读中断优先级寄存器来确定哪一个中断被优先执行。 当多重中断源请求中断时,硬件优先级逻辑会判断哪一个中断将被执行;同时,硬件逻辑将会执行位于0x18(或0x1C)地址处的指令,再由软件编程识别各个中断源,然后再根据中断源跳转到相应的中断处理程序。
4.2中断控制 4.2.1 程序状态寄存器的F位和I位 如果CPSR(程序状态寄存器)的F位被设置为1,那么CPU将不接受来自中断控制器的FIQ(快速中断请求);如果CPSR程序状态寄存器的I位被设置为1,那么CPU将不接受来自中断控制器的IRQ(通用中断请求)。因此,为了使能FIQ和IRQ,必须先将CPSR程序状态寄存器的F位和I位清零,并且中断屏蔽寄存器INTMSK中相应的位也要清零。 在使用C语言编写控制程序时,CPSR在程序中是不可见的。F位和I位清零可由中断屏蔽寄存器INTMSK中相应的位清零自动完成。
4.2.2 中断模式(INTMOD) S3C2410提供了两种中断模式,即FIQ(快速)模式和IRQ(通用)模式。所有的中断源在中断请求时都要确定使用那一种中断模式。INTMOD相应位为0,选通用中断模式;INTMOD相应位为1,选快速中断模式。上电或复位时INTMOD相应位为0,默认选通用中断模式。
4.2.3 中断挂起寄存器(INTPND)和中断源挂起寄存器 (SRCPND) S3C2410有两个中断挂起寄存器:中断源挂起寄存器(SRCPND)和中断挂起寄存器(INTPND)。这两个寄存器用于指示对应的中断源和中断是否被激活。当中断源请求中断时,SRCPND寄存器的相应位被置1;当中断被激活时,INTPND寄存器的相应位被置1。 如果屏蔽位被设置为1,则相应的SRCPND位会被置1,而INTPND寄存器不会有变化;如果INTPND被置位,只要标志I或标志F被清零,就会执行相应的中断服务子程序。在中断服务子程序中要先向SRCPND中的相应位写1来清除挂起状态,再用同样的方法来清除INTPND相应位的挂起状态。 注意:可以通过INTPND= INTPND来实现清零,以避免写入不正确的数据引起错误。 4.2.4 中断屏蔽寄存器(INTMSK) 当INTMSK寄存器的相应位(屏蔽位)为1时,对应的中断被禁止;当INTMSK寄存器的屏蔽位为0时,则相应的中断正常实行。如果一个中断的屏蔽位为1,则该中断请求不被受理。
4.2.5 中断优先寄存器 (PRIORITY) 上面已介绍过,S3C2410共有56个中断源,有26个中断控制器,外部中断EXTIN8~23共用一个中断控制器,外部中断EXTIN4~7共用一个中断控制器,9个UART中断分成3组,共用3个中断控制器,ADC和触摸屏共用一个中断控制器。中断的优先级是由主组号和从ID号的级别控制,具体见表4-1。 中断优先级设置模块如图4-2所示: 图4-2中断优先级设置图
从上图可以看出,中断优先级产生模块共有7个中断仲裁器(AIRBITER0~AIRBITER6),每个中断仲裁器是否使能由寄存器PRIORITY[6:0]决定,每个中断仲裁器下面有4~6个中断源,这些中断源对应着REQ0~REQ5这6个优先级。 每个中断仲裁器可以控制6个中断请求的优先顺序(ARB_MODE),仲裁器和中断请求的优先顺序如表4-1示:
其中,REQ 0中断优先级总是最高的,REQ5中断优先级总是最低的。
4.3 S3C2410中断源 表4-2所示为S3C2410的56个中断源。在56个中断源中,有30个中断源提供给中断控制器,其中,外部中断EINT4~EINT7通过“或”的形式提供一个中断源送至中断控制器,EINT8~EINT23也通过“或”的形式提供一个中断源送至中断控制器。 56个中断源具体来说: EINT0~EINT23(24个)、nBATT_FLT(1个)、INT_TICK(1个)、INT_WDT(1个)、INT_TIMER0~INT_TIMER4(5个)、INT_UART0~INT_UART2(各3个,共9个)、INT_LCD(2个)、INT_DMA0~INT_DMA3(4个)、INT_SDI(1个)、INT_SPI0~INT_SPI1(2个)、INT_USBD(1个)、INT_USBH(1个)、INT_IIC(1个)、INT_RTC(1个)、INT_ADC(2个),共56个。
4.4 中断控制专用寄存器 在4.2节中已介绍中断控制器有5个,但S3C2410有8个寄存器与中断有关,有5个专用于中断控制:源挂起寄存器(SRCPND)、中断模式寄存器(INTMOD)、中断屏蔽寄存器(INTMSK)、中断优先权寄存器(PRIORITY)和中断挂起寄存器(INTPND),与中断有关的寄存器如表4-3所列。 中断源发出的中断请求首先被寄存在中断源挂起寄存器(SRCPND)中,中断模式寄存器INTMOD把中断请求分为两组:快速中断请求(FIQ)和通用中断请求(IRQ),中断优先权寄存器(PRIORITY)处理中断的优先级。
4.4.1 IRQ偏移寄存器(INTOFFSET) 除上面介绍的5个中断控制寄存器以外,还有几个寄存器与中断控制有关。 中断偏移寄存器INTOFFSET给出IRQ模式的中断请求中被响应的中断的地址(哪个IRQ模式的中断请求被响应)。
4.4.2 外部中断控制寄存器(EXTINTn) S3C2410的24个外部中断有几种中断触发方式,EXTINTn配置外部中断的触发类型是电平触发还是边沿触发以及触发的极性。EXTINT[2 :0]的具体配置参考数据手册。 4.4.3 外部中断屏蔽寄存器(EINTMASK) EINTMASK[23:4]分别对应外部中断23~4,该位等于1,对应外部中断被屏蔽;该位等于0,对应外部中断被使能,EINTMASK[3 :0〕保留。
4.5 中断控制程序编写步骤 4.5.1 主程序工作 • 先清除中断源挂起寄存器(SRCPND)和中断挂起寄存器(INTPND),可用rSRCPND= rSRCPND和rINTPND=r INTPND来完成; • 设中断模式,这里使用通用中断,rINTMOD=0x00000000;因上电或复位时rINTMOD是清0的,这步也可以不做。 • I/O口初始化,有些中断源要通过I/O口向CPU申请中断,如外部中断0(EXTINT0)通过F口的GPF0、外部中断11(EXTINT11)通过G口的GPG3向CPU申请中断,此时两个口的控制寄存器GPFCON和GPGCON的要设置成:GPFCON[1:0]=1,0;GPGCON[7:6]=1,0。具体见下章I/O口介绍。 • 设中断服务函数地址,S3C2410在2410addr.h中定义了40个宏,设置了系统支持的中断服务函数的指针,设中断服务函数地址就是把我们编写的中断服务函数的地址(就是中断服务函数的名字)赋予相应的函数指针。函数指针定义如下:
// ISR #define pISR_RESET (*(unsigned *)(_ISR_STARTADDRESS+0x0)) #define pISR_UNDEF (*(unsigned *)(_ISR_STARTADDRESS+0x4)) #define pISR_SWI (*(unsigned *)(_ISR_STARTADDRESS+0x8)) #define pISR_PABORT (*(unsigned *)(_ISR_STARTADDRESS+0xc)) #define pISR_DABORT (*(unsigned *)(_ISR_STARTADDRESS+0x10)) #define pISR_RESERVED (*(unsigned *)(_ISR_STARTADDRESS+0x14)) #define pISR_IRQ (*(unsigned *)(_ISR_STARTADDRESS+0x18)) #define pISR_FIQ (*(unsigned *)(_ISR_STARTADDRESS+0x1c))
#define pISR_EINT0 (*(unsigned *)(_ISR_STARTADDRESS+0x20)) #define pISR_EINT3 (*(unsigned *)(_ISR_STARTADDRESS+0x2c)) #define pISR_EINT4_7 (*(unsigned *)(_ISR_STARTADDRESS+0x30)) #define pISR_EINT8_23 (*(unsigned *)(_ISR_STARTADDRESS+0x34)) #define pISR_NOTUSED6 (*(unsigned *)(_ISR_STARTADDRESS+0x38)) #define pISR_BAT_FLT (*(unsigned *)(_ISR_STARTADDRESS+0x3c)) #define pISR_TICK (*(unsigned *)(_ISR_STARTADDRESS+0x40))
#define pISR_WDT (*(unsigned *)(_ISR_STARTADDRESS+0x44)) #define pISR_TIMER0 (*(unsigned *)(_ISR_STARTADDRESS+0x48)) #define pISR_TIMER1 (*(unsigned *)(_ISR_STARTADDRESS+0x4c)) #define pISR_TIMER2 (*(unsigned *)(_ISR_STARTADDRESS+0x50)) #define pISR_TIMER3 (*(unsigned *)(_ISR_STARTADDRESS+0x54)) #define pISR_TIMER4 (*(unsigned *)(_ISR_STARTADDRESS+0x58)) #define pISR_UART2 (*(unsigned *)(_ISR_STARTADDRESS+0x5c)) #define pISR_LCD (*(unsigned *)(_ISR_STARTADDRESS+0x60)) #define pISR_DMA0 (*(unsigned *)(_ISR_STARTADDRESS+0x64)) #define pISR_DMA1 (*(unsigned *)(_ISR_STARTADDRESS+0x68))
#define pISR_DMA2 (*(unsigned *)(_ISR_STARTADDRESS+0x6c)) #define pISR_SDI (*(unsigned *)(_ISR_STARTADDRESS+0x74)) #define pISR_SPI0 (*(unsigned *)(_ISR_STARTADDRESS+0x78)) #define pISR_UART1 (*(unsigned *)(_ISR_STARTADDRESS+0x7c)) #define pISR_NOTUSED24 (*(unsigned *)(_ISR_STARTADDRESS+0x80)) #define pISR_USBD (*(unsigned *)(_ISR_STARTADDRESS+0x84)) #define pISR_USBH (*(unsigned *)(_ISR_STARTADDRESS+0x88)) #define pISR_IIC (*(unsigned *)(_ISR_STARTADDRESS+0x8c)) #define pISR_UART0 (*(unsigned *)(_ISR_STARTADDRESS+0x90))
#define pISR_SPI1 (*(unsigned *)(_ISR_STARTADDRESS+0x94)) #define pISR_RTC (*(unsigned *)(_ISR_STARTADDRESS+0x98)) #define pISR_ADC (*(unsigned *)(_ISR_STARTADDRESS+0x9c)) 从上面可以看出,每个中断源的中断服务函数指针名是固定的:pISR+中断源。 • 设中断触发方式,触发方式有5种,有上升沿、下降沿、双沿、低电平、高电平触发方式,外部中断触发方式在外部中断控制寄存器(EXTINTn)中设定。如EINT0触发方式在EXTINT0[2:0] 中设定,[2:0]=000低电平、001高电平、01X下降沿、10X上升沿、11X双沿触发,更详细内容见S3C2410.pdf.。 • 取消总中断屏蔽和子中断屏蔽,等待中断,如下面实验例程通过rEINTMASK&=~(1<<11);rINTMASK&=~(BIT_EINT0|BIT_EINT8_23);来实现。
4.5.2 中断服务程序工作 • 在中断服务程序中,先屏蔽中断,防止其他中断产生干扰我们中断服务程序的执行; • 执行中断服务程序; • 在中断服务程序中,先屏蔽中断,防止其他中断产生干扰我们中断服务程序的执行; • 执行中断服务程序; • 清中断源挂起寄存器(SRCPND)和中断挂起寄存器(INTPND); • 取消总中断屏蔽和子中断屏蔽,等待新中断产生; • 中断返回。
4.5.3 中断服务程序示例 在主程序中,系统初始化后,程序进入死循环,等待中断。 同时,初始化定时器1,设定时器中断时间,当设定时器定时时间到,产生中断。 在北京精仪达盛科技公司EL-ARM830教学实验系统中,接有两个LED发光管,两个LED发光管的阴极分别接I/O口G的bit8和bit9,阳极通过电阻接电源。 在中断服务程序中,把LED1和LED2两只发光管循环亮灭,每循环亮灭一次,说明来一次中断。关于定时器操作,可参考第十一章内容。
//引入头文件 #include <math.h> #include "2410LIB.h" #include "2410SLIB.h" #include "2410ADDR.h" #include "option.h" #include "mmu.h" #include "def.h" #include "target.h" #include <string.h> #include "config.h" //------------------------------------------------------------------------ // 主程序 void Main(void){ sys_init(); while(1); }
//---------------------------------------------------------------------------- // 定时器1初始化程序 void Timer1_init(void) { rGPGCON = rGPGCON & 0xfff0ffff | 0x00050000; //配置GPG口为信号输出 rGPGDAT = rGPGDAT | 0x300; rTCFG0 = 255; // Prescaler0=255 rTCFG1 = 0 << 4; // rTCNTB1 = 48828; // 在pclk=50MHZ下,1秒钟的记数值rTCNTB1 = 50000000 / 4 / 256 = 48828; rTCMPB1 = 0x00; rTCON = (1 << 11) | (1 << 9) | (0 << 8); //禁用定时器1,手动加载 rTCON = (1 << 11) | (0 << 9) | (1 << 8); //启动定时器1,自动装载 }
//-------------------------------------------------------------------------- // 定时器中断服务子程序 int flag; void __irq Timer1_ISR( void ) { if (flag == 0) rGPGDAT = rGPGDAT & 0xeff | 0x200; flag = 1; } else { rGPGDAT = rGPGDAT & 0xdff | 0x100; flag = 0; rSRCPND |= BIT_TIMER1; rINTPND |= BIT_TIMER1;
//-------------------------------------------------------------------------- // 定时器中断初始化程序 void Timer1INT_Init(void) //定时器接口使能 { if ((rINTPND & BIT_TIMER1)) rSRCPND |= BIT_TIMER1; } pISR_TIMER1 = (int)Timer1_ISR; rINTMSK &= ~(BIT_TIMER1); //开中断; // 目标板初始化程序,主函数中只需调用此函数,即可完成目标板的初始化
void sys_init(void) { MMU_Init(); ChangeClockDivider(1,1); // 1:2:4 ChangeMPllValue(0xa1,0x3,0x1); // FCLK=202.8MHz Isr_Init(); Port_Init(); Timer1_init(); Timer1INT_Init(); Uart_Init(0,115200); Uart_Select(0); }
第四章习题与练习 1,S3C2410的中断模式有哪两种? S3C2410的中断控制寄存器有几个,每个的作用是什么? 如何清除中断请求? 如何使能某中断源申请的中断? 如何屏蔽某中断源申请的中断? 7, 外部中断0(EXTINT0)通过F口的GPF0、外部中断11(EXTINT11)通过G口的GPG3向CPU申请中断,此时两个口的控制寄存器GPFCON和GPGCON如何设置? 8,阅读例子程序,熟悉中断程序编写步骤。 9,如何绕过项目和仿真器设置以及项目初始化程序的编写困难,快速完成嵌入式程序设计? 10,S3C2410中断有几种触发方式?如何选择中断触发方式?
第五章 S3C2410的I/O口和I/O操作 S3C2410芯片上共有71个多功能的输人/输出引脚,它们分为8组I/O端口。 • 1个23位输出端口(端口A); • 2个11位输人/输出端口(端口B, H); • 4个16位输入/输出端口(端口C,D,E,G); • 1个8位输人/输出端口(端口F)。 可以很容易地通过每组端口来满足不同系统配置和设计的需要。在运行程序之前,必须 对每个用到的引脚功能进行设置。如果某些引脚的复用功能(第二功能)没有使用,那么可以先将该引脚设置为I/O口。
5.1 S3C2410 I/O口描述 • 端口控制寄存器(GPACON~GPHCON)。 • 端口数据寄存器(GPADAT~GPHDAT)。如果该端口定义为输出端口,那么可以向PnDAT的相应位写数据。如果该端口定义为输人端端口,可以从PnDAT的相应位读入数据。 • 端口上拉寄存器(GPBUP~GPHUP)。端口上拉寄存器控制每个端口组上拉电阻的使能/禁止。如果某一位为0,则相应的上拉电阻被使能(上电复位状态),端口做输人/输出端口(第一功能口);如果是1则相应的上拉电阻被禁止,端口做多功能口(第二功能口)。如果端口的上拉电阻使能,无论在哪种状态(INPUT、OUTPUT、DATAn、和EINTn等下,)上拉电阻都起作用。
• 多状态控制寄存器。该寄存器控制数据端口的上拉电阻,包括高阻态、USB 和CLKOUT选项。 • 外部中断控制寄存器(EXTINTN) 。24个外部中断有各种各样的中断请求信号,EXTINTN寄存器可以配置信号的类型有低电平触发中断请求、高电平触发中断清求、下降沿触发中断请求、上升沿触发中断请求,以及两沿触发方式中断清求。 • 8个外部中断引脚有数字滤波器(参考数据手册中的EINTFI.Tn)。 • 有16个外部中断 (E1NT[15:0]) 用于唤醒CPU。 • 掉电模式和I/O端口。在掉电模式下仍然保持所有的GPIO状态值,可以参考相应章节的内容。EINTMASK在掉电模式下也不能阻止唤醒CPU。如果EINTMASK屏蔽了EINT[15:4]的某一位,仍然可以唤醒CPU;但是SRCPND的EINT[4:7]位和EINT[8:23]位不能在CPU唤醒后马上被置位。
5.2 I/O端口控制寄存器 5.2.1 端口A控制寄存器(GPACON、GPADAT)和功能配置 表5-1 S3C2410端口A控制寄存器 S3C2410 I/O端口A控制寄存器及端口A功能配置分别如表5-1表5-2所示。 表5-1 S3C2410端口A控制寄存器
表5-2 端口A功能配置 GPACON[22:0]中的某一清零,与该位相对应的引脚为输出口;置位相应的引脚为第二功能端口。 端口被配置为输出引脚后,引脚的状态和相应的位状态一致。当端口被配置为第二功能引脚后,读出来的值不确定。
5.2.2 端口B控制寄存器(GPBCON、GPBDAT和GPBUP)和功能配置 表5-3 S3C2410端口B控制寄存器 若端口B被配置为输入端口,则可以从引脚上读入相应的外部输入的数据。如果端口B被配置为输出端口,则向该位写人的数据可以被发送到相应的引脚上。如果该引脚被配置为第二功能引脚,则读出的数据不确定。 若清位GPBUP[10:0]中的某一位,则允许端口B的相应引脚的上拉功能,否则禁止上拉功能。
表5-4 端口B控制寄存器(GPBCON)的配置 5.2.3 端口C控制寄存器(GPCCON、GPCDAT和GPCUP) 和功能配置 端口C控制寄存器(GPCCON、GPCDAT和GPCUP) 和具体配置如表5-5和5-6所示。
表5-5 端口C控制寄存器(GPCCON)的配置
5.2.4 端口D控制寄存器(GPDCON、GPDDAT和GPDUP)和功能配置 如果端口C被配置为输人端口,则可以从引脚读入相应外部输入源输入的数据。如果端口C被配置为输出端口,则向寄存器写的数据可以被送往相应的引脚。如果端口C被配置为第二功能引脚,则从该引脚读出的数据不确定。 若清位GPCUP [15:0」的某一位,则允许端口C相应引脚的上拉功能,否则禁止上拉功能。 5.2.4 端口D控制寄存器(GPDCON、GPDDAT和GPDUP)和功能配置 端口D控制寄存器(GPDCON)的具体配置情况如表5-7和表-8所示。 表5-7 端口D控制寄存器( GPDCON)的配置
表5-8 端口D控制寄存器( GPDCON)的配置 如果端口D被配置为输入端口,则可以从引脚读入相应外部输入源输入的数据。如果端口D被配置为输出端口,则向寄存器写的数据可以被送往相应的引脚。如果端口D被配置为第二功能引脚,则从该引脚读出的数据不确定。 若清位GPDUP[15:0]的某一位,则允许端口D相应引脚的上拉功能,否则禁止上拉功能。
5.2.5 端口E控制寄存器(GPECON、GPEDAT和GPEUP) 和功能配置
表5-10 端口E控制寄存器(GPECON)的配置
5.2.6 端口F控制寄存器(GPFCON、GPFDAT和GPFUP)和功能配置 端口E控制寄存器(GPECON)的配置如表5-9和5-10所示。 如果端口E被配置为输入端口,则可以从引脚读入相应外部输入源输入的数据。如果端口E被配置为输出端口,则向寄存器写的数据可以被送往相应的引脚。如果端口E被配置为第二功能引脚,则从该引脚读出的数据不确定。 若清位GPEUP[15:0]的某一位,则允许端口E相应引脚的上拉功能,否则禁止上拉功能 5.2.6 端口F控制寄存器(GPFCON、GPFDAT和GPFUP)和功能配置 端口F控制寄存器(GPFCON)的配置如表5-l1和-12所示。 如果端口F被配置为输入端口,则可以从引脚读入相应外部输入源输入的数据。如果端口F被配置为输出端口,向寄存器写的数据可以被送往相应的引脚。如果端口F被配置为第二功能引脚,则从该引脚读入的数据不确定。 若清位GPFUP[15:0]的某一位,则允许端口F相应引脚的上拉功能,否则禁止相应引脚上拉功能。
表5-11 端口F控制寄存器( GPFCON) 表5-12 端口F控制寄存器(GPFCON)的配置
5.2.7 端口G控制寄存器(GPGCON、GPGDAT和GPGUP)和功能配置 端口G控制寄存器(GPGCON)的配置如表5-13和5-14所示。
如果端口G被配置为输入端口,可以从引脚读入相应外部输入源输入的数据。如果端口G被配置为输出端口,向寄存器写的数据可以被送往相应的引脚。如果端口G被配置为第二功能引脚,则从该引脚读出的数据不确定。 若清位GPGUP[15:0]的某一位,则允许端口G相应引脚上的上拉功能,否则禁止相应引脚上拉功能。
5.2.8 端口H控制寄存器(GPHCON、GPHDAT和GPHUP)和功能配置 端口H被配置为输入端口,可以从引脚读入相应外部输入源输入的数据。如果端口H被配置为输出端口,向寄存器写的数据可以被送往相应的引脚。如果端口H被配置为第二功能引脚,则从该引脚读出的数据不确定。 若清位GPHUP[15:0]的某一位,则允许端口H相应引脚的上拉功能,否则禁止相应引脚上拉功能。端口H控制寄存器(GPHCON、GPHDAT和GPHUP)和端口B功能配置基本相同,见表5-15,5-16。 表5-15端口H控制寄存器
表5-16 端口H控制寄存器(GPHCON)的配置
5.3 I/O口操作步骤 5.31 上拉寄存器和控制寄存器设置 I/O口上拉寄存器和控制寄存器设置比较简单,首先确定I/O口工作模式,如果是工作在第二功能状态,则上拉电阻功能禁止,即GPBUP~GPHUP中相应位置1;如果工作在基本输入/输出状态,则上拉电阻功能允许,此时因上电或复位时GPBUP~GPHUP初值为0,所以在程序中不用设置。 I/O口数据寄存器中每一位输入/输出功能大多由I/O口控制寄存器中两位控制,如GPHDATA[0],即GPH0的输入/输出功能,由GPHCON[1:0]控制,GPHCON[1:0]=0 0,该位作输入;GPHCON[1:0]=0 1,该位作输出;GPHCON[1:0]=1 0,该位作nCTS0;GPHCON[1:0]=1 1,系统保留没用。其他各口与此相同,编写I/O程序时一定注意GPnCON和GPnDATA中位的对应关系。 I/O口与外围设备连接一般要通过光电隔离或其他隔离器件,直接相连一定要确认负载不能超过4个与非门。光电隔离一是可保护微处理器;二是可进行电平转换;三是可对某些信号进行分配,所以在一般情况下都要加。
5.3 I/O口编程示例 在北京精仪达盛科技公司的EL-ARM830教学实验系统上有两个LED发光二极管,它们的阴极接在S3C2410 G口的8(bit8)脚和9(bit9)脚,阳极经电阻接电源5V,如果GPG8或GPG9输出低电平,相应LED亮;如果GPG8或GPG9输出高电平,相应LED灭。控制程序使这两个LED管循环亮灭。
//----------------------------------------------------------------------------- // GPG8,GPG9轮流输出低电平,使两个LED循环亮灭 void Main(void){ int flag, i; sys_init(); for(;;){ if(flag==0) { for(i=0;i<1000000;i++); //延时 rGPGCON = rGPGCON & 0xfff5f0ff | 0x00050000; // GPGCON[17:16]=01,GPH8输出;GPGCON[19:18]=01 GPH9输出。 rGPGDAT = rGPGDAT & 0xeff | 0x200; //GPG9低电平,GPG8高电平LED2亮,LED1灭 for(i=0;i<10000000;i++); //延时 flag = 1;
} else { for(i=0;i<1000000;i++); //延时 rGPGCON = rGPGCON & 0xfffff0ff | 0x00050000; // GPGCON[17:16]=01,GPH8输出;GPGCON[19:18]=01 GPH9输出。 rGPGDAT = rGPGDAT & 0xdff | 0x100; //GPG8低电平,GPG9高电平LED1亮,LED2灭 flag = 0; }
第五章习题与练习 1,S3C2410有多少组I/O口?每组包括的I/O口的有哪些? 2,I/O口A~H功能有哪些不同? 5, 程序中rGPFCON=0x5500,rGPFCON=0x55aa 是什么含意? 6,I/O口做第一功能和I/O口做第二功能,应该使用哪个寄存器进行设定,如何设定? 7,I/O口做输入输出时为什么要加隔离器件? 8,GPB1输出控制蜂鸣器工作,低电平有效,rGPBCON应如何配置?使蜂鸣器鸣响或不鸣响,rGPBDAT应如何配置?