加入收藏 | 设为首页 | 会员中心 | 我要投稿 | RSSRSS-巴斯仪表网
您当前的位置:首页 > 电子发烧 > 单片机学习

ARM LINUX在EP7312上的移植

时间:2013-09-08  来源:123485.com  作者:9stone

摘要:Linux是一种支持多种体系结构处理器的操作系统,有很强的移植性。描述了将ARMLinux移植到基于EP7312处理器的目标板上的方法与过程。首先介绍了EP7312处理器和ARM Linux,并简单说明了如何搭建移植环境,然后着重讨论了在该开发板上bootloader的设计实现以及ARMLinux内核的移植的方法,最后对在这种基于Linux的嵌入式系统环境下如何开发应用程序作了探索和展望。

1  引言
    ARM处理器是一种32位的嵌入式RISC处理器。在众多同种类型的处理器中,ARM系列已经成为了当今应用范围最广的嵌入式芯片。第1枚ARM芯片诞生于1983年1O月到1985年4月之问的英国,当时属于Acorn公司,是Acorn RISC Machine的简写。为了扩展市场,ARM产品线在成为Acorn公司的核心之后,被独立分割出来,成立了ARM公司,变成了Advanced RISC Machine的缩写。
    根据市场调查,2001年初,ARM的32位处理器的市场占有率已经超过了75%。
    ARM公司是知识产权(Intellectual Properly)供应商,它负责ARM处理器的芯片设计,转让设计许可,由合作伙伴公司来生产使用ARM处理器核的各具特色的芯片。
    ARM公司在全世界范围内有超过100个这样的合作伙伴。在芯片特点上,ARM处理器核耗电少,成本低,功能强,还特有16/32位双指令集,这使得ARM成为了移动通信、手持计算、多媒体数字消费等嵌入式解决方案的RISC标准。ARM的产品线主要包括ARM7 Thumb家族和ARM9 Thumb家族、ARM10 Thumb家族以及StrongARM家族。

2 基于ARM的EP7312处理器和ARM Linux
    在本文中使用的目标平台EP7312是Cirrus Logic公司使用ARM7 Thumb家族中ARM 720T处理器内核开发的一块SoC(System-on-Chip)嵌入式微处理器。
    EP7312专门为PDA、Internet设备、移动电话和手持设备等设计成超低功耗和高性能的微处理器。它的核心逻辑部件ARM720T采用了具有8K字节的4路集合关联(set-associative)独立cache和一个写缓存,并且还包含了一块加强的MMU(内存管理部件)。这些特性使得开发人员可以将Windows CE和Linux等操作系统移植到基于这块微处理器的目标系统中。
    Linux是一种被广泛移植到各种嵌入式平台的开放源代码操作系统。ARM Linux是一个将Linux内核移植到各种基于ARM处理器的目标系统的项目,由Russell King<rmk@arm.1inux.org.uk>主持,已经为超过100种不同的目标机器成功完成了移植工作,包括有基于AKM的计算机、网络设备和目标板等。
    本文的工作主要包括bootloader的设计实现、ARMLinux内核移植、嵌入式系统应用开发方法探索3个部分。

3 移植环境的建立
    嵌入式系统的开发与一般的应用开发最大的差别就在于:前者需要建立特殊的硬件环境,而后者一般基于特定的操作系统或者分布式平台。后者的平台已经对硬件或者网络媒质做了抽象,从而不需要由系统开发者来完成这些工作。而在嵌入式系统开发中,这也由开发者完成。
    嵌入式系统开发环境一般分成主机端(HOST)和目标板(TARGET)两个部分。主机端是开发平台,用于运行开发过程中的各种工具;目标板是运行和测试平台,是嵌入式系统的最终驻留环境。在主机端和目标板之间需要通过某种方式进行通信,如使用RS232C串口。这种通信的目的在于发送控制指令和传输数据,同时获得反馈信息。图1是本文中系统移植工作的硬件环境:
 
    图1  系统移植工作的硬件环境
    主机端的PC使用COM1和EP7312的UART1相连接,因为RS232C和UART的电气特性不同,在连接两者的串口线上使用了一块HIN232CP芯片完成电平转换。通过RS232C串口完成对目标板的必要控制功能。
    EP7312开发板上配备有一块CS8900A以太网卡芯片,和主机端建立原始(raw)IP连接,使用链路层地址(以太网MAC地址)完成大批量数据的传送。
    硬件环境建立之后,就需要创建软件开发环境。软件环境主要是指ARM体系结构的交叉编译环境,在主机端使用RedHatLinux 7.1操作系统,并在其上建立gcc的ARM体系结构的交叉开发环境。交叉编译环境所需的源代码软件包有下面这些:

  1.     binutils-2.11.2.tar.gz
        binutils里面包括GNU的链接器ld、汇编代码编译器as、用来将文件打包重组的ar以及为ar打包的文件建立符号表的ranlib等工具。
  2.     linux-2.4.17.tar.gz,patch-2.4.17-rmk5.gz
        交叉开发环境的编译过程中需要Linux内和源代码中的头文件。
  3.    gcc-2.95.3.tar.gz和gcc-2.95.3.diff.bz2
       gcc是GNU的C编译器,可以配置编译为多种体系结构目标的交叉编译器。这里配置为arm-elf-编译目标(TARGET)。
  4.     glibc-2.2.3.tar.gz和glibc-linuxthreads-2.2.3.tar.gz
        gee使用的C函数库和针对Linux的线程库。

    将这些软件包按照如下顺序进行编译:
    binutils→内核头文件→gcc→glibc
    交叉开发环境建立后,在目标板上运行的可执行代码都由它来编译链接。

4 Bootloader 的设计实现
    Bootloader被用作系统从硬件启动到操作系统启动的过渡,是嵌入式系统中必不可少的一段程序。它相当于PC机中的BIOS和OS Loader,用于初始化运行硬件和启动操作系统,因此其实现方式由硬件的特性决定。和BIOS/OS Loader一样,它需要固化在目标板中,每次启动目标板时,首先会运行bootloader,在它完成CPU和相关硬件的初始化之后,才从事先规定的地址启动操作系统或者嵌入式应用的固化程序。
    在嵌入式系统开发过程中,bootloader还担任了与主机端通信的任务,它相当于一个“服务器”,不断监从主机端传来的控制信息和数据信息,完成相应的操作。
    EP7312处理器根据nMEDCHG引脚接入电平的不同,触发两种启动模式:内部启动模式和外部启动模式。启动模式的不同会使系统地址映射发生变化,表1是两种启动模式下的系统地址映射表。
 
表1 EP7312系统地址映射表
    不论是采用哪一种启动方式,系统都是从地址Ox00000000,也就是地址映射的最起始位置开始执行指令。
    由于外部启动是从外部Flash开始的,本文的bootLoader不考虑这种启动的情况,而只针对于内部启动。EP7312采用内部启动时,首先会执行片内ROM中的一段只有128个字节长的汇编代码。这128个字节的程序只能从串口中读取2K字节并把这2K的代码存放到地址值为0x10000000的内部SRAM中,然后PC就跳转到地址0x10000000开始运行这下载下来的2K代码,因此我们用于在目标板运行的bootloader的大小必须限制在2K字节以内,并用这段可执行程序来实现下面的功能:

  1. 设置EP7312的控制寄存器SYSCON2和SYSCON3;
  2. 初始化SDRAM控制器,完成SDRAM的侦测;
  3. 初始化地址扩展控制寄存器;
  4. 实现网卡控制芯片CS8900A的驱动:
  5. 将PC寄存器指向Linux内核存放的地址,运行操作系统。

    为了使存放于目标板上的可执行代码小于2K字节,我们将bootloader的代码分成两部分,一部分存放于主机端,另一部分存放于目标板上,两者通过串口进行通信。通过这种方法来减小目标板上的代码量,并且依靠主机端与目标板的协同工作来启动Linux内核。在目标板上的程序主要完成下面的任务:

  1. 从串口接收从主机端发送过来的信息;
  2. 根据主机端不同的命令调用相应的写控制寄存器函数来设置各个控制芯片;
  3. 通过串口或者网卡芯片接收大块数据,并把它写到SDRAM中的指定地址;
  4. 完成一个任务后通过串口向主机端发送一个反馈信息。

    在主机端完成的任务如下:

  1. 解释输入的命令行参数;
  2. 打开主机端的串口和网卡控制芯片;
  3. 根据命令行参数决定向目标板发送命令的顺序。
  4. 向目标板传送需要改写的控制寄存器的地址和控制字;
  5. 读入内核映像文件,通过串口或者网卡将数据发送给目标板。

    图2描述了bootloader的工作流程。
 
图2 Bootloader的运行流程

5 Linux内核的移植
    我们使用的Linux内核版本是2.4.17,采用ARMLinux的补丁是patch-2.4.17-rmk5。完成ARMLinux内核到EP7312体系结构的移植,需要修改所有和体系结构相关的代码。其中主要的部分是内核入口部分、处理器和体系结构初始化部分、IO端口映射部分和中断初始化部分。除此之外,还有EP7312相关设备的驱动程序,如CS8900A以太网接口的驱动等。
    要把ARMLinux移植到EP7312上,首先必须搞清楚内核入口代码head-armv.S(arch/arm/kernel/)。head-armv.S所需要完成的任务主要集中在下面的一段代码中:

mov r0,#F_BIT|I_BIT|MODE SVC @make sure svc mode
 msr cpsr_c,r0                                 @and all irqs disabled
bl_lookup_processor_type
teq r10,#0                                         @invalid processor?
moveq r0,#'p'                                   @yes,error'p'
beq_error
bl_lookup architecture_type
teq r7,#0                                          @invalid architecture?
moveq r0,#'a'                               @yes,error'a'
beq_error
bl_create_page_tables
adr lr, ret                                          @retum address
add pc,r10,#12                               @initialise processor
                                                          @(return control reg)

    在这里内核检查Linux内核代码中的相关信息与目标板处理器中寄存器中的相关值是否相匹配。处理器寄存器中的值由bootloader传递过来,里面的具体内容是从EP7312的控制寄存器中得到。Linux内核中的相关信息存放在内核的.proc.info段和.arch.info段中(Linux内核映像文件的布局由GNU的连接脚本所决定),它们用_proc_info_begin、_arch_info_begin和~proc_info_end、_arch_info_end作为开始与结束的标识。.proc.info段中的具体的内容定义在arch/arm/mrn/proc.arm720.S文件中,主要包括CPU值、MMU的控制字、一组处理器的操作函数等信息。.arch.info段的内容则是通过系统中的一组宏来定义,定义的内容包括体系类型、内存和I/O的起始地址、系统参数存放的起始地址、体系修正函数、UO映射函数和中断初始化函数。
     Linux内核和bootloader做好协调,才能在运行过程中查找到正确的函数,启动Linux内核。
    当Linux内核能够在EP7312芯片上运行起来后,还需要在内核中加入开发板上其它控制器和设备的驱动,这里最重要的是网卡驱动。
    EP7312开发板中所带的网卡芯片是Cirrus Logic公司的CS8900A。Linux2.4.17中有i386体系结构下的CS8900A驱动程序代码,不过没有在ARM体系结构下的驱动,因此需要把它移植到EP7312开发板上。
    在Linux内核代码中CS8900A的侦测函数是cs89x0_probe,首先需要让内核在启动时能够执行这个函数,用以侦测开发板上的CS8900A芯片。
    Linux内核用net_device结构来描述一块网卡,结构中的init项指向(或者间接指向)每个网卡驱动的侦测函数。系统中存在一个net_device结构的链表,如图3所示:
 
图3 内核中网络接口结构链表
    表明在内核启动时可以最多侦测8块网卡,通过扫描这个链表,就可以执行网卡驱动的侦测函数。Linux利用GNL C编译器的C扩展属性功能,将一系列设备初始化函数统一放到initcall.init段中,然后在内核启动时将存放在这个段中函数逐个执行。因此,只要将eth0_dev中的init项指向CS8900A的侦测函数,并且将扫描net_device结构链表的函数放到initcall.init段中就可以在内核启动时执行CS8900A的侦测函数。
    在修改CS8900A的侦测函数时需要注意的是,CS8900A有两种工作模式:存储模式和I/O模式。由于在bootloader中并没有设定存储模式,因此只能用CS8900A缺省的I/O模式来访问其内部的PacketPage。侦测函数中原先使用存储模式访问Packet Page的地方,需要改用I/O模式访问而且还要考虑8个I/O访问端口的地址问题。

6 结  语
    嵌入式Linux系统的根文件系统通常是以Ramdisk的方式存在的,Ramdisk的映像文件一般以压缩的形式存放在Flash中,在内核启动时将这个压缩的文件解压存放到内存中再作为根文件系统装载。由于在应用程序开发期间常常需要改动Ramdisk中的内容,采用前面所说的方法就会经常写Flash而比较费时。我们可以通过使用bootloader将Ramdisk直接下载到SDRAM中的方法来解决这个问题。
    Linux内核启动时,有几个重要的函数与Linux的内存管理相关,这两个函数的实现方式会影响到将Ramdisk直接下载到SDRAM中的方法的实现。
    这些函数的处理过程是:在建立的内核内存分配器时,它会统计系统SDRAM的大小然后建立一张相应大小的位图来跟踪内存中的空闲页面。由于开发板的SDRAM的大小是16MBytes的,位图只需占用一个页面,大小为4K,存放的位置紧跟着内核,如图4所示。接着,系统把存放内核之后的内存区域,也就是end标签之后的空间全部视为空闲区域,位图也会把对应这片空间内存页的位置为0。有了这张跟踪内存使用情况的位图之后,系统可以很方便地将所有置0位所对应的内存页面清空。
 
图4系统内存布局
    由于上面的这种内存初始化方法,使得存放Ramdisk的内存区域也被清空了,因此在内核启动之后就无法找到Ramdisk了。可以根据存放Ramdisk的起始和结束地址来计算出位图中相对应的位,并在系统将这些位置0之后,重新将它置1。这样,之后的系统操作中就不会将Ramdisk给清除了。
    为了进一步方便应用程序的开发和调试,在内核加上网卡驱动后可以使用NFS的方法。在主机端开启一个NFS服务之后,不需要将编译好的程序放到Ramdisk的映像文件中而只要把它放到主机端的一个NFS输出目录,在目标板上再将这个目录挂载上就可以了。


分享到:
来顶一下
返回首页
返回首页
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表
栏目导航->单片机学习
  • 电子应用基础
  • 电源技术
  • 无线传输技术
  • 信号处理
  • PCB设计
  • EDA技术
  • 单片机学习
  • 电子工具设备
  • 技术文章
  • 精彩拆解欣赏
  • 推荐资讯
    使用普通运放的仪表放大器
    使用普通运放的仪表放
    3V与5V混合系统中逻辑器接口问题
    3V与5V混合系统中逻辑
    数字PID控制及其改进算法的应用
    数字PID控制及其改进
    恶劣环境下的高性价比AD信号处理数据采集系统
    恶劣环境下的高性价比
    栏目更新
    栏目热门