采用ARM+Linux 2.6 内核的仪器控制系统设计

发布者:RadiantSoul最新更新时间:2010-12-23 来源: 现代电子技术关键字:ARM  Linux  结构体  开源 手机看文章 扫描二维码
随时随地手机看文章

      0 引 言

  嵌入式系统的开发都有其特殊的应用场合与特定功能,而嵌入式Linux操作系统因其开源和广泛的处理器支持、易于移植而备受行业青睐。AT91RM9200是Atmel公司针对系统控制、通信领域推出的基于ARM920T内核的32位RISC微处理器,它具有小体积,低功耗,低成本及高性能等特点,其内部集成了SPI、串口、PIO、以太网、EBI、USB、MCI等多种接口。

  在Linux系统中,应用层不可以直接操作硬件,需设计驱动程序向下屏蔽硬件特性,实现硬件与用户间的通信。系统平台为在虚拟机中安装Fedora 8,目标系统采用Linux 2.6.21.7内核,定制文件系统建立NFS根文件系统,使用双网卡方式搭建成交叉开发环境,并使用超级终端或minicom作为控制台。

  l 设备驱动程序设计

  该控制系统框架如图1所示。ARM通过USARTl接收外来的控制命令,通过SPI接口和通用PIO口与外部设备通信,达到控制作用。在Linux下,所有的设备以文件的形式来使用。其中Linux已经提供了支持AT91RM9200的SPI驱动,DBGU和UART驱动,只要对其源代码进行一些修改并在编译内核时将其选中就可以直接使用。所以主要集中在PIO口驱动设计中,外部设备使用一个.PB29引脚(即IRQO)作为外部中断信号提供给ARM,另外使用一些I/O引脚对外部设备进行控制。

  Linux设备分为3类:字符设备、块设备和网络设备,该系统设计的是模块化字符设备驱动程序。Linux 2.6内核与Linux 2.4内核主要有3点不同:

  (1)内核的API变化,增加了不少新功能;

  (2)提供了sysfs用于描述设备树;

  (3)驱动模块从.o变为.ko。

  1.1 驱动程序重要数据结构

  打开的设备在内核内部由file结构标识,内核使用file_operaTIons结构访问驱动程序的函数。file_opera_tions结构是一个定义在中的函数指针数组。下面主要介绍常用的几个成员:

  在这些函数指针中,open和release用于设备的打开和关闭,是每个驱动程序必须实现的函数。其他函数根据实际需要来实现,在该项目中实现方式如下:

  另一个重要数据结构是file结构体,主要包括以下成员:

  它代表一个打开的文件,只出现在内核空间,与用户空间的file是不同的。在open操作时创建,然后传递给file_operations的其他函数指针,直到close。

  第三个重要数据结构即inode,其成员包括:dev_ti_rdev和struet cdev*i_cdev,其中i_rdev中包含实际设备号,可以通过下面两个宏函数获取主从设备号:

  初始化file_operations结构体后,要将其中定义的各个方法如open,release,write,read,ioctl等一一实现。其函数名即初始化这个file_operations结构体时各成员函数指针。当在用户空间调用open时,内核空间的open方法即相应操作,其他方法同理。

  1.2 驱动初始化和卸载清理工作

  驱动加载需要进行设备注册等一系列初始化工作;并且在卸载驱动时要释放资源进行一些清理工作以使其不影响内核。所以定义两个函数static int devctl_init()和static void devctl_exit(),然后通过module_init(devctl_init)和module_exit(devctl_exit)来通知内核。为了维护Linux的开源性,调用下面的宏来声明:

  在初始化函数中,首先进行设备的注册。主设备号表示对应的驱动程序,次设备号由内核使用,用于正确确定设备文件所指的设备。可以动态申请或者静态申请设备号。动态申请使用下面的函数:

  dev是一个只输出的参数,它在函数成功完成时持有分配范围的第一个数;firstminor是请求的第一个要用的次编号;count是请求的连续设备编号的总数;name为设备名,返回值小于0表示分配失败。然后通过major=MMOR(dev)获取主设备号。如果注册不成功或者卸载驱动时需要取消设备的注册,使用下面的函数实现(其参数含义同上):

  对于字符型设备还要定义一个cdev结构体变量,并使用cdev_init()初始化,然后调用cdev_add()通知内核添加一个字符设备。同样在卸载时要使用cdev_del()移除,否则用户使用驱动时,有时不能打开设备。因为不使用cdev或者cdev在模块卸载时不删除会导致内核处在一个不稳定状态,在用户层可能无法打开设备文件。  1.3 I/O端口访问

  在系统控制要求中,需要访问ARM的I/O端口,包括普通I/O口和复用为IRQO的PB29引脚,然而Linux中对I/O端12和I/0内存的读写指令中使用的都是虚拟地址,所以在访问前要先将物理寄存器地址映射到I/O内存。有两种方法实现地址映射,一种是使用ioremap为I/O内存区域分配虚拟地址,用iounmap取消,另一种是使用内核已经定义好的虚拟地址。这里主要介绍第二种方式。

  对于AT91RM9200利用如下转换函数获取虚拟地址,其中宏AT91_VA_BASE_SYS是系统虚拟基地址:

  读写端口对于AT91RM9200还可使用专门函数

  int at9 1_set_gpio_value(unsigned pin,int value),并包含头文件asm-arm/arch-at91/gpio.h。一般端口的访问在驱动模块初始化时申请资源,在卸载时释放资源,而对于I/O口的使能则在open方法中实现,相应的禁用在release方法中实现。

  1.4 ioctl方法的实现

  用户可以通过ioctl方法向内核发送各种命令,必要时传递参数,下面展示一个简单实例。

  1.5 中断控制实现

  当外部信号的到来时刻不可预测时,使用轮询方式将使得效率极低,需要使用阻塞型中断实现。即没有中断信号到来时阻塞读进程,使其处于睡眠状态,当中断到来唤醒读进程,执行预定处理操作。

  首先,在open方法中使用request_irq()安装中断处理程序,在release方法中释放。函数原型如下:

  其中:参数irq为中断号;handler为ISR指针;flags为与中断管理有关的各选项字节掩码;dev_name即设备名;dev_id为中断信号线。

  其次,ISR为申请中断时使用的参数名,假设为irq0_handler,定义原型如下:

  中断阻塞即在其内部调用void wake_up_inter-rupTIble(wait_queue_head_t*queue)实现,然后返回IRQ_HANDLED;在read方法中调用wait_event_in-terruptible(queue,condition)来唤醒读进程,这样,当用户程序读设备时,如果没有中断到来,读进程将进入睡眠状态,中断发生被唤醒。

  对于中断信号IRQO,因是PB29复用,要配置为外设A[4],同时还要配置中断源类型,函数分别在#in

  2 编译和调试

  驱动程序可静态编译进内核,也可编译成模块动态加载。为便于调试采用动态模块加载方式,Linux 2.6内核下驱动编译方式和Linux 2.4版明显不同,其建立的Makefile只需简单地写入obj-m:=devctl.O(假设源文件为devctl.c),然后执行命令:make-C/usr/lo-cal/arm/Linux-2.6.21.7 SUBDIRS="MYMPWDmodules",注意内核源文件目录因各自系统而异,然后将生成的.ko文件置于目标系统的/home目录下,使用insmod加载模块,并使用cat/proc/devices命令查看分配到的设备号,使用mknod创建设备节点,卸载模块使用rmmod命令。

  为方便调试,可以在适当使用printk打印信息,还可以通过点LED等以便于发现问题。

  3 结 语

  通过对相关的Linux 2.6内核中驱动源码的深入研究与自我设计实践,不断调试,在此阐述的方法得到实际验证,并已成功使用到某仪器的控制系统中。Linux博大精深,其开源的特点必将吸引更多的开发者投入其中,使其更好发展,应用于更多领域。

关键字:ARM  Linux  结构体  开源 引用地址:采用ARM+Linux 2.6 内核的仪器控制系统设计

上一篇:嵌入式软件与硬件的集成测试过程研究
下一篇:基于ARM和Linux的字符采集与识别系统

推荐阅读最新更新时间:2024-05-02 21:13

初识ARM cotex—A9
1) 电阻的作用 接在电源和参考点之间的电阻 (1) 作用: 使参考点的电平默认为高电平 接在地和参考点之间的电阻 (1) 作用: 使参考点的电平默认为低电平 2) 局部性原理 程序执行时,访问的数据和执行的指令往往在一个局部范围内。 3)bus 可以接多个设备的一组线叫总线 (1) CPU总线 CPU(ALU和控制器)连接内存和IO设备的一组线, 用于传输: 地址、数据和控制 地址线 数据线 控制线 (2) 单总线(ARM) 内存和IO设备接在相同cpu总线上,表现为:
[单片机]
ARM7和ARM9流水对PC的影响
“PC=PC+1”,这不完全正确,PC自增一的情况指出现在无流水(non-pipeline)的情况下,这个时候取指,译码,执指都是顺序执行的。 而在有流水的情况下就比较复杂了这里用arm7和arm9为例。 arm7是3级流水。arm9是5级流水。PC在执行过程中是每次加8的。原因如下: 为便于说明问题,我们假设当前正在执行0地址处的指令,从下面的两幅图中可以清楚地得到结论。 ARM7是三级流水线,AMR7的三级流水线如下: ARM9是五级流水线,ARM9的五级流水线如下: 可见,ARM9和ARM7中都是PC=当前执行指令地址+8的根本的原因是,两者的流水线设计中,指令的执行阶段都是处于流水线的第
[单片机]
ARM学习《八》——STM32定时器配置及其中断设置!
好久没有写东西了,工作太忙都快没时间学习了。今天调试了STM32的定时器功能,STM32定时器比较多,但调试都是一样的,寄存器都是一一对应的。就拿TIM2举例说明。在网上搜了好多关于定时器的设置,但大多数都是一个版本,而且都是针对库函数操作的,让人看起来一头雾水,对于初学者很是不利(我也是初学者)。下面我将自己的定时器设置过程一一记录下来,以供大家参考,我们共同学习 首先定义定时器头文件,也就是定义寄存器以供操作: //************************************************************************* // // TIM2-Register //
[单片机]
多路数据采集系统的设计与实现
0 引言 随着物联网技术的发展与应用,A/D数据采集是其中一项重要的研究课题,A/D多路采集系统实现方案可以多种,通过对三种实现方案进行比较,最终采用STM32系列ARM芯片进行设计。STM32是基于ARM Cortex-M3内核的32位处理器,具有杰出的功耗控制以及众多的外设,并具有极高的性价比,目前正逐渐抢占了电子领域原有的51、AVR的市场。本设计中采用STM32F103RBT6作为主控制器,该芯片配置丰富,便于今后的系统功能扩展。 1 方案比较与论证 为实现多路数据采集要求,提出如下三种设计方案: (1)基于单片机的数据采集系统 本方案采用双单片机的方法,即在数据采集的远端、近端均采用单片机控制,远端完成
[单片机]
多路数据采集系统的设计与实现
arm-linux-qt环境的建立
Arm-Linux嵌入式QT/E环境的建立(qt/e 3.x系列) QT/E 3.x系列比QT/E 2.x系列有非常大的改进,大大提高了开发进度,不再使用tmake,安装也更简单。但目前在网上关于QT/E 3.x系列的介绍还是比较少, 所以本文介绍一下QT/E 3.x系列的安装。 一、建立arm交叉编译工具链 在安装QT/E之前,应确保arm-linux交叉编译工具链已经建立,如果还没有可以参考以下步骤建立。 1、下载交叉编译工具cross-2.95.3.tar.bz2(或其他版本如:cross-3.4.4.tar.bz2),这是已经制作好的arm交叉编译工具链,只需解压及建交环境变量即可使用。 2、把文件cross-2
[单片机]
ARM中断向量两种设置方法
在32位ARM系统中,一般都是在中断向量表中放置一条分支指令或PC寄存器加载指令,实现程序跳转到中断服务例程的功能。例如:   IRQEntry B HandleIRQ ;跳转范围较小   B HandleFIQ   或IRQEntry LDR PC,=HandleIRQ ;跳转的范围是任意32位地址空间   LDR PC,=HandleFIQ   LDR伪指令等效生成1条存储读取指令和1条32位常数定义指令。32位常数存储在LDR指令附近的存储单元中,相对偏移小于4KB。该32位数据就是要跳转到的中断服务程序入口地址。   之所以使用LDR伪指令,是因为ARM的RISC指令为单字指令,不能装载32位的立即数(常数),
[模拟电子]
ARM笔记:外部中断
一、概念 中断分为两大类:外部中断和内部中断。 1、外部中断:S3C2440的24个外部中断占用GPF0~GPF7(EINT0~EINT7)、 GPG0~GPG15(EINT8~EINT23)。使用这些引脚作为中断输入时,必须将引脚配置为EINT模式,配置方法可参考datasheet。 2、内部中断:内部中断包括DMA中断、UART中断、IIC中断等等由内部外设触发的中断。 3、相关寄存器:S3C2440中断控制涉及到10个寄存器-- SRCPND、INTMOD、INTMSK、PRIORITY、INTPND、INTOFFSET、SUBSRCPND、INTSUBMSK、EINT
[单片机]
<font color='red'>ARM</font>笔记:外部中断
s3c2440 ARM9 裸机驱动第一篇-GPIO驱动(C)
此文为对于LED驱动的补充: 废话不说,先上代码。 start.s .text .global _start _start: ldr r0 ,= 0x53000000 @WATCHDOG ADD mov r1 ,#0x0 str r1 , @r1 的数据写入r0 关看门狗 ldr sp ,=1024*4 @设置栈 bl main @跳转到main执行 halt: b halt led.c #define GPFCON (*(volatile unsigned long *)0x56000050) #define
[单片机]
小广播
最新嵌入式文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved