kaiyun官方注册
您所在的位置: 首页> 嵌入式技术> 设计应用> MAX1202在嵌入式系统中的驱动程序设计及应用
MAX1202在嵌入式系统中的驱动程序设计及应用
2014年微型机与应用第24期
陈 晨,王进华
(福州大学 电气工程与自动化学院,福建 福州 350108)
摘要:首先介绍了MAX1202的基本性能和特点,详细阐述了MAX1202在嵌入式Linux中驱动程序的实现方法,最后介绍了编写应用程序测试驱动程序的基本方法,为嵌入式Linux系统下的驱动设计提供一个模板。
Abstract:
Key words :

摘 要: 首先介绍了MAX1202的基本性能和特点,详细阐述了MAX1202在嵌入式Linux驱动程序的实现方法,最后介绍了编写应用程序测试驱动程序的基本方法,为嵌入式Linux系统下的驱动设计提供一个模板。

关键词: MAX1202;驱动程序;A/D转换;嵌入式Linux

0 引言

  科技的进步使智能化设备越来越多地应用到工业生产、农业种植、医疗卫生、航天设备甚至是居民的日常生活中,智能化设备要处理一些环境中的物理量就需要使用相关传感器将其转化成电量,如电压、电流等。但是这些量要送给处理器处理,则必须要通过模/数转换器进行转换。

  本文中采用MAX1202模/数转换器和友善之臂的Micro2440开发板,开发板使用三星公司的s3c2440的ARM9微处理器。在Linux系统中开发MAX1202驱动程序并编写应用程序进行驱动程序的测试。

1 芯片介绍

  MAX1202是一款8通道12位串行A/D转换器。串行接口工作频率最高可以达到2 MHz[1]。工作采用单端+5 V供电或双端±5 V供电。内部有一个8通道的多路转换器、高带宽的跟踪/保持电路以及高转换速度和低功耗的串行接口,芯片提供了符合SPI通信标准的SPI接口,以便于编程实现数据的转换。

  其典型应用电路如图1所示。

001.jpg

2 驱动程序设计

  Linux驱动程序使用module_init宏中所定义的初始化函数注册该驱动及初始化硬件设备;使用module_exit宏中定义的注销函数注销设备,释放相关资源。

  结构struct file_operations列出了设备驱动程序可供应用程序调用的所有函数。其中的成员都是函数指针,指向该函数的入口执行位置,当应用程序调用open、read、write等函数时,驱动程序会通过该结构找到对应应该执行的M1202函数,进而根据传入的参数执行,以响应应用程序的调用。驱动程序的编写主要就在于file_operations结构体中各驱动函数的实现,并不是每一个函数都要实现[2],对于不需要实现的函数可以赋值为空,也可以在函数实现中直接返回0,或直接调用系统默认的实现函数。MAX1202的file_operations结构体定义如下:

  static const struct file_operations M1202_fops=

  {

  .owner=THIS_MODULE,

  .open=M1202_open,

  .read=M1202_read,

  .write=M1202_write,

  .ioctl=NULL,

  };

2.1 模块初始化函数M1202_init

  在驱动加载时,系统进程会通过module_init(M1202_init)宏找到所定义的驱动初始化函数M1202_init(),进行驱动程序的加载。主设备号可以自已定义,向函数MKDEV(M1202_major,0)传递主次设备号产生dev_t类型的devno结构[3];也可以由alloc_chrdev_region(&devno,0,1,M1202_name)函数自动分配主设备号;本例中自己定义主设备号,然后由register_chrdev_region(devno,1,M1202_name)函数在Linux中为驱动程序获取设备编号;接着就是向Linux内核注册字符设备,指出该驱动可提供给应用程序的接口结构。实现代码如下:

  cdev_init(&M1202Cdev,&M1202_fops);

  M1202Cdev.owner=THIS_MODULE;

  M1202Cdev.ops=& M1202_fops;

  cdev_add(&M1202Cdev,devno,1);

  代码中省去了错误调试信息。

 2.2 设备打开函数M1202_open

  s3c2440芯片配备了2组SPI接口[4],Micro2440开发板引出了一组SPI1,对应是PA7、PA8、PA9、PA10引脚,这是一组可以复用的端口,既可以用中断、普通端口,也可以用于SPI通信。MAX1202在外部时钟模式下的工作时序如图2所示。

002.jpg

  查看MAX1202在外部时钟模式下的工作时序可以发现,在控制字送入的8个时钟后,芯片即开始了边输出边转换的过程,相比较内部时钟模式的转换完成后再读取输出结果而言,有着更快的转换效率,故采用外部时钟模式。在控制字输出后,转换结果紧跟着输出,为了减少频繁对寄存器的操作,降低编程的难度,采用普通输出端口轮流输出高低电平的方法模拟主SPI设备的时钟输出。使用s3c2410_gpio_cfgpin(S3C2410_GPG11,S3C2410_GPG11_OUTP);将GPG11端配置成输出端口用于输出MAX1202工作时所需的片选信号;类似地用s3c2410_gpio_cfgpin()函数配置GPG6、GPG7端为输出端,分别用于产生MAX1202的控制字输入与时钟输入;使用s3c2410_gpio_cfgpin(S3C2410_GPG5,S3C2410_GPG5_INP);将GPG5端口配置成输入端口,用于读取MAX1202的Dout端的输出结果。在MAX1202正式工作前需将片选端CS端置为1,相应地有s3c2410_gpio_setpin(S3C2410_GPG3,1);函数;另外三个端口s3c2410_gpio_setpin函数配置为0。这些就是open函数所需要完成的端口配置。

 2.3 写函数M1202_write

  设备打开后,每次转换之前,需要向MAX1202写控制字,以设置MAX1202选通的工作通道、时钟模式、信号输入模式等。MAX1202控制字格式如表1所示。

004.jpg

  Bit7:起始位一般选择1,用于标识控制字的开始;

  Bit6~Bit4:是8路通道的选择,在单端模式下,依据8421编码,000对应第0通道CH0,001对应第1通道CH1,010对应第2通道CH2,以此类推;

  Bit3:为信号的单双极性选择位,这里选择1,单极性;

  Bit2:为信号输入方式选择位,这里选择1,单端输入;

  Bit1~Bit0:时钟和断电模式选择位,这里选择11,外部时钟。

  驱动属于内核的一部分,而应用程序属于用户空间,内核空间和用户空间的数据不能共享,数据的传输需要使用特定的函数copy_from_user()和copy_to_user()。因此,由应用程序传入的控制字信息需要使用copy_from_user()传入内核空间。使用循环移位和与操作,轮流读取8位控制字的每一位,由s3c2410_gpio_setpin(S3C2410_GPG6,X)函数将各位值输出到MAX1202得DIN端,在时钟的下降沿由MAX1202读取,X代表了要传输的一位值。

 2.4 读函数M1202_read

  在外部时钟模式下,控制字输入完后即可在紧接着的16个时钟周期内读取转换结果,这16位转换结果的最低4位为无效位,均为0,虽然无效,但必须在时钟的作用下读取出来,不然会影响到下一次的转换结果,故函数读取16位后左移4位用于消除低4位的无效位。while函数的执行条件控制读取次数为16次,s3c2410_gpio_getpin(S3C2410_GPG5)用于从MAX1202的DOUT端读入当前时钟下的输出值。读取结束后,要使用copy_to_user()函数将得到的结果传递到用户空间,以供显示或处理。

2.5 模块卸载函数M1202_exit

  模块卸载函数首先要删除字符设备,然后释放占用的驱动设备号,以供其他的设备使用。

  cdev_del(&M1202Cdev);

  unregister_chrdev_region(MKDEV(M1202_major,0),1);

3 MAX1202在嵌入式系统中的应用

  3.1 设备驱动的加载

  Linux下的驱动有静态加载和动态加载两种方式[5]。静态加载将驱动程序编译到内核里,系统启动后直接可以由应用程序调用,但每次修改驱动程序都必须重新编译内核,较麻烦。动态加载是在系统启动后使用insmod命令,把编译好的M1202.ko文件加载到系统中,不需要时可以使用rmmod命令卸载。但是在重新开机之后,该驱动就没了,需要重新加载。故静态加载适合于驱动开发完成后的产品量化;而动态加载适合于驱动开发过程中频繁的修改。

  在开发板中驱动的动态加载方法:

  #cd/lib/modules/2.6.32.3-FriendlyARM

  #insmod M1202.ko

  #mknod/dev/M1202 c 55 0

  在Linux中,设备被当做文件一样处理,任何可用设备在/dev/目录下都会有一个对应的设备文件,使用mknod命令创建设备节点,在应用程序中即可像操作文件一样操作该设备。

 3.2 数据采集

  驱动加载并且创建了设备节点后就可以编写应用程序进行电压数据的采集。

  使用open函数以只读的方式打开已经创建了的M1202节点即打开了MAX1202硬件。传入控制字0x8F给write函数,开启通道0的转换,使用单极性单端输入外部时钟模式,read函数将转换结果保存到指针num所指向的地址中,然后就可以打印或者处理转换结果,最后像关闭文件一样使用close()函数关闭设备。使用交叉编译指令#arm-linux-gcc╞o M1202test M1202test.c编译后生成应用程序文件M1202test,通过串口导入Micro2440中或将应用程序文件放到网络根文件系统中,#chmod+x M1202test增加文件的可执行权限,#./M1202test执行可执行文件,即可对通道0引脚的数据进行采集转换。

  部分应用程序如下:

  int fd=open(“/dev/M1202”,0_RDWR);

  int ctlword=0x8F;

  write(fd,ctlword,1);

  read(fd,&num,2);

  printf(“num=%d\n”,num);

  close(fd);

  在实际使用中可以使用for(int i=0,i<8,i++)和ctlword=ctlword|(i<<4);改变控制字的Bit6-Bit4位,循环采集引脚0-7端输入的电压,或者根据需要使用其中部分引脚。经测试,A/D转换结果较好,在转换误差范围内。

4 结论

  随着智能化设备的发展,嵌入式系统将涉及生活中的方方面面。本文详细介绍了MAX1202在嵌入式Linux系统中的驱动程序的开发方法,对于相关驱动程序的开发有一定的参考价值,且该MAX1202的A/D实现方法也可以应用到一些工程实际中去。

参考文献

  [1] 蒋双梅,高敦堂,都思丹.8通道12位串行A/D转换器MAX1202及其应用[J].微电子学,2000,30(6):437-440.

  [2] 韦东山.嵌入式Linux应用开发完全手册(第1版)[M].北京:人民邮电出版社,2008.

  [3] 付兴武,张军,王洋.基于SPI总线协议的字符设备驱动程序[J].计算机系统应用,2013,22(2):146-150.

  [4] 杨小容,陈建政.串口AD嵌入式Linux驱动实现[J].中国测试,2010,36(2):84-87.

  [5] 黄智伟,邓月明,王彦.ARM9嵌入式系统设计基础教程(第1版)[M].北京:北京航空航天大学出版社,2008.


此内容为AET网站原创,未经授权禁止转载。
Baidu
map