基于ARM7与µClinux 的嵌入式系统多串口设计<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
曹 凯,凌 明
(东南大学 国家ASIC工程中心 集成电路学院 江苏 南京 210096)
摘要:针对基于ARM7内核微处理器和 µClinux操作系统的嵌入式系统,介绍了利用IMP<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />16C554 芯片对其进行多串口扩展。给出了系统设计方案,详细阐述了多串口设备驱动程序的设计方法,并重点介绍了对IMP16C554 芯片的初始化设
置和基于中断工作模式的扩展串行接口编程。
关键词:嵌入式系统;µClinux;ARM;多串口。
中图分类号:TP271 文献标识码:B 文章编号:1004-373X(2007)02-094-03
Design of the Multiple Serial Ports for Embedded System Based on ARM7 and µClinux
CAO KAI ,LING MING
(IC Academy National ASIC Engineering Centre,Southeast University,Nanjing ,210096,China)
Abstract: Multiple serial ports extension with chip INP16C554 is conducted to the embedded system based on ARM7 kernel microprocessor and µClinux OS. Besides method of the system project,the design procedure of multiple serial ports is depicted,as well as hardware setting initialization of IMP16C554 and asynchronous uart port programming on interruption working mode。
Keywords:embedded system;µClinux;ARM;multiple serial ports
1 引 言
嵌入式系统以其性能/成本优势和灵活方便的使用等特点,在工业控制、通信、航空航天、军事技术等领域取得了广泛的应用。尤其在商业管理和信息家电方面,伴随着今天计算机技术和集成电路技术的飞速发展,嵌入式系统的应用由于巨大的市场需求得到迅猛的增长。
由于处理器速度、应用软件规模和系统复杂度的提高,嵌入式系统越来越依赖于嵌入式操作系统的支持来管理系统软、硬件资源和系统应用。µClinux操作系统提供了对没有内存管理单元的微处理器和对实时性要求不高的应用的支持。因其稳定的性能、良好的可移植性、强大的网络功能、对硬件的广泛支持、以及开源的特点,在当今主流嵌入。式操作系统中占有重要的地位。SEP3203是东南大学国家ASIC中心设计的一款的16/32位RISC微处理器。他内嵌ARM7TDMI内核,采用0.25µm工艺,工作频率75MHz。其低功耗、高性价比优点和所提供的完整的通用外设接口,非常适合小型嵌入式应用的需求。
在嵌入式系统中,串行通讯接口作为常用的与外部设备的数据通信接口,在数据通信方式中占有重要地位,如用于连接MODEM,host机通讯、串口监控设备、可编程逻辑控制器(PLC)等。因此,一旦需要同时连接多个外部串口设备,微处理器原有的串口资源就无法满足应用需求。本文介绍对采用ARM7内核的SEP3203进行µClinux嵌入式操作系统设备驱动开发,来实现微处理器与外围设备串口连接的扩展。
2 系统硬件设计
本设计使用IMP16C554 为SEP3203 微处理器扩展了4个RS485 通信串口,构成一个多串口的设备远程监控系统。该系统的主要功能是获取多个本地设备的工作数据并发送串口设备控制指令。
2.1 多串口接口芯片
在本设计中采用的IMP16C554 是具有4个通用异步接收和发送(UART)接口的串行接口芯片,带有4组独立的16字节收发FIFO,能同时完成4个通道的收发。他还提供一个可编程的波特率发生器,发送和接收频率在50Hz~1.5MHz之间选择。IMP16C554 的片上状态寄存器可提供数据传输过程发生错误的类型、状态信息。此外,IMP16C554 还提供了完整的Modem 控制功能和内部Loop-back 片上自诊断功能。
2.2 串口扩展电路
硬件设计主要包括微处理器与IMP16C554之间的通信接口问题。其中包括他们之间进行联络的应答信号,利用总线进行数据传递的一组数据线,产生片选信号和串口芯片内部寄存器选择的接口连线。
电路连接原理框图如图1所示。
在电路设计中,利用了SEP3203的外部存储接口模块(EMI)为串口芯片配置了地址。选择空闲的存储体F的位置,将nCSF 片选信号用于选择串口芯片。但是,IMP16C554 本身并没有片选输入,只有4个串行通道的选择信号(#CSA~#CSD)。所以,使用微处理器的地址线A3,A4,通过nCSF作为片选信号的地址译码电路来选择串口芯片4个串行通道A,B,C,D中的1个或多个通道。
同时,IMP16C554的数据线D0~D7直接与微处理器的数据总线相连,进行串口数据的传送。片内寄存器选择线A0~A2与微处理器的A0~A2地址线连接。读写信号#IOR,#IOW 分别连到微处理器的nOE,nWE信号端口。微处理器的GPIO口接收分别来自4个UART的中断请求(INTA~INTS),以及收发FIFO的就绪信号 (#RXRDY,#TXRDT)并按照规定的时序产生前面提到的通道选择、读写等信号来同串口芯片进行交互。
此外,本设计串行通信协议采用RS485 作为接口标准,与串行接口芯片的CMOS电平不同。因此,在串口芯片IMP16C554和串行口之间选用了MAX3485芯片来进行电平的转换。
3 串口驱动程序设计
3.1设备驱动程序简介
设备驱动程序在Linux内核中发挥着非常重要的作用。他们使得所驱动的硬件设备相对于内核来说变成一个定义良好的内部编程接口,同时完全隐藏了硬件设备的工作细节。因而使得内核对外部硬件设备的操作就像对一个普通文件进行读写一样。
设备文件可以使用同操作普通文件相同的,标准的系统调用接口来完成打开/关闭、读写、以及I/O控制等操作。而设备驱动程序的任务就是实现这些操作的系统调用接口函数。
开放源代码的µClinux嵌入式操作系统在内核中提供了串口设备驱动。但由于扩展串口设备硬件工作方式的不同,需在参考原有串口驱动程序的基础上重新设计多串口设备驱动程序。
3.2 设备驱动程序架构
Linux内核的I/O子系统向内核中其他部分提供了一个统一的标准设备接口,通过在include/linux/fs.h中提供的file_operations数据结构来完成。file_operations数据结构提供了设备驱动函数调用的入口点,应用程序对设备进行各项操作就是通过这些入口点调用相应的操作函数。例如,当应用程序对设备文件执行读操作时,内核通过file_operations数据结构查到Read函数的入口地址,从而调用Read函数。
多串口设备驱动程序的设计基本可按照Linux字符型设备驱动程序的架构进行。设备驱动程序大致可由如下几个部分构成:驱动程序的注册与注销、设备的打开与释放、设备的读写操作、设备的控制操作、设备的中断处理。
在Linux操作系统中,内核对设备的管理是通过设备号来进行的。这可以在设备初始化过程中调用register_chrdev()函数来完成。而关闭设备则是通过调用unregister_chrdev()从内核中注销程序,同时释放占用的设备号。
在多串口设备驱动程序中,在init_module()函数中用以下语句进行“quadserial”设备的注册:int result="register"_chrdev(GFD_QS_MAJOR,“quadserial”,&qs_fops);
其中,GFD_QS_MAJOR即设备主设备号的宏定义名。相应地,下面的语句在函数cleanup_module()中完成“quadserial”设备的注销。
unregister_chrdev(GFD_QS_MAJOR,“quadserial”);
打开和释放设备是通过调用file_operations 结构中的open()与=release()函数来进行的。open()通常完成的工作是:检查设备相关错误,进行设备初始化工作,通过次设备号识别具体的设备,分配和填写放在file→private_data中的数据结构。release()函数的作用正好相反,释放对设备的控制权,释放设备数据占用的内存和中断等。
设备的读写操作相对简单。对于字符设备,使用read()和write()函数分别进行读写操作(同样在file_operations结构注册入口地址中)。在多串口设备驱动程序中,由于微处理器通过数据总线连接多串口芯片来读写数据,所以具体在read()和write()函数中使用系统提供的I/O端口读写函数inb(),outb()进行。
除了读写操作,经常还需要对设备进行某些控制操作,如波特率的设置。这可以通过file_operations结构中的ioctl ()函数来完成。ioctl()的用法与具体的设备密切相关,需要根据设备的实际情况分析。
使用中断工作方式来响应设备事件时,要在设备初始化代码中登记设备中断和编写中断处理函数。下面的语句进行“quadserial”设备中断的登记,其中QS_IRQ是多串口设备使用的GPIO口中断号的宏定义名。handle_qs_irqn是接收数据中断处理函数名:
err = request_irq(QS_IRQn,handle_qs_irqn,O,“quadserial”,NULL);
总之,多串口设备驱动程序是按照Linux字符型设备驱动架构来进行编写的。而具体的设备驱动程序设计的重点主要在硬件的初始化设置和中断处理函数的设计上。
3.3 多串口初始化
多串口设备的初始化主要涉及多串口芯片的初始化以及微处理器GPIO口工作方式的初始化设置。
多串口芯片的初始化工作就是设置其内部寄存器的初始值参数,包括串行通信时数据位数、停止位数、奇偶检验、中断方式以及发送和接收的波特率等。可分为设置FIFO工作模式和设置异步通信数据格式2方面。IMP16C554的寄存器包括接收保持寄存器RHR、发送保持寄存器THR,FIFO控制寄存器FCR中断使能寄存器IER、中断状态寄存器ISR线形状态寄存器以及设置波特率的DLL,DLM 寄存器等。可通过地址线A0~A2来选择这些片内寄存器(可写的),对他们进行设置。
IMP16C554的FIFO有2种工作方式:查询方式和中断方式。在查询工作方式下,占用系统时间过多。降低了系统的性能。同时,微处理器SEP3203提供了18个外部中断源,已足够本系统使用。因而在本设计中采用中断工作方式。这样,多串口芯片的4个串口通道都独立地工作在中断方式下,保证了系统内部的高速通信。同时FIFO中触发级(Trugger Level)的选择也保证了多串口通道的中断处理不会彼此影响而发生FIFO数据溢出。
另外,对用到的GPIO口要设定其工作方式,比如中断输入或数据输入/输出。设定的过程须按硬件文档规定的设置顺序进行。
3.4 中断和缓冲区处理
对工作在半双工方式的RS485 串口来说,系统采用中断来实现软件流控。4个串口独立工作在中断工作方式下。采用中断工作方式来实现数据的收发就是当串口接收数据时CPU响应中断,并将相应的中断标志置位,然后处理相应的中断程序。在中断处理程序中,在接收数据时将接收FIFO中的数据读入缓冲区,而发送数据时将缓冲区数据写入发送FIFO。
首先,驱动程序在系统初始化串口时使串口的接收使能,等待接收数据。当有数据被传送过来时就可在数据接收中断处理程序中顺利接收。而在系统要发送本地数据时,则先使能串口发送,然后发送数据。
针对硬中断驱动的异步串口数据收发,为每个串口建立了两个环行缓冲区TxBuffer[n],RxBuffer[n]来实现上层驱动程序与底层硬件的数据传递。环行缓冲区采用“先进先出(FIFO)”的调度策略,两个指针分别指向数据的排头和排尾,保证新存入的数据不会覆盖尚未得到处理的数据。需要发送数据时,上层驱动程序把准备好的数据送入环行缓冲区TxBuffer[n],再由中断处理程序从环行缓冲
区TxBuffer[n]取出并发送。而当中断处理程序接收到串口送来的数据时,将其存入接收环行缓冲区RxBuffer[n],上层驱动程序就可以从该环行缓冲区取出数据了。环形缓冲区操作所使用的控制块结构如下:
struct bufferblock{
int b_start;
int b_end;
int count;
char * buf;
}
其中count域表示当前缓冲区内的现有数据长度;b_start表示数据排头,即从当前环形缓冲区中读取数据的指针位置;b_end表示数据排尾 ,即往当前环形缓冲区中存放数据的指针位置;buf指针指向缓冲区的首地址。
上层程序对缓冲区进行读写的程序代码示例如下:
static char * get_from_rxbuffer(int num){
int temp_start = RxBuffer[num].b_start; /* 保存初始缓冲区数据头标志 */
if(RxBuffer[num].count==0)return; /* 如果缓冲区为空则退出 */
RxBuffer[num].count――; /* 缓冲区数据计数减1 */
if(RxBuffer[num].b_start+1==BUFFER_LENGTH)Rxbuffer[nem].b_start==0;/* 数据头标志回到缓冲区首地址 */
else
RxBuffer[num].b_start ++; /* 数据头标志递增 */
return (RxBuffer[nem].buf+temp_start);
/* 返回原来数据头标志处的数据地址 */
}
static int put_in_txbuffer(int num,char data){
if(TxBuffer[num].count==BUFFER_LENGTH)return-ENOBUFS;
/* 如果缓冲区满则退出 */
*(TxBuffer[num].buf+TxBuffer[num].b_end)=data;
/* 将写入的数据放到数据尾标志处 */
if(TxBuffer[num].b_end+1==BUFFER_LENGTH)TxBuffer[num].b_end=0;
/* 数据尾标志回到缓冲区首地址 */
else
TxBuffer[num].b_end++; /* 数据尾标志递增 */
TxBuffer[num].count++; /* 缓冲区数据计数加1 */
return 0;
}
4 多串口驱动模块的加载
Linux系统可以采用的动态和静态2种驱动程序模块加载方式,而µClinux只支持静态的驱动程序加载方式,也就是将驱动程序直接加入到内核中再重新编译内核。
整个多串口设备驱动程序编译过程包括:将驱动程序添加到µClinux 内核源文件字符设备驱动程序目录(µClinux-dist/linux-2.4.x/driver/char/)下;修改该目录下的Makefile文件,添加编译该设备语句;修改该目录下的Config.in文件,添加在编译时的设备选定提示菜单选项;在$µClinux-dist/vendor/GFD/Garfield/makefile文件中为扩展的4个串口添加设备节点ttyS2~ttyS5;最后是按顺序使用编译命令,生成包含多串口设备驱动的内核二进制文件。具体设备驱动模块加载和编译命令的使用方法此处不再赘述。 至此模块加载和内核编译过程结束,可将编译生成的内核二进制文件通过调试工具下载到系统硬件上调试运行。
5 结 语
本设计通过采用通用的IMP16C554串口扩展芯片,为基于ARM7内核芯片SEP3203和µClinux操作系统的嵌入式系统进行了串口扩展。从而实现了嵌入式系统同多个外部设备的串口通信,使系统能够进行多个设备的数据采集,完成设备监控任务。
参考文献
[1] Alessandro Rubini.Linux设备驱动程序[M].3版.北京:中国电力出版社,2006。
[2] Garfield SEP3203移动终端应用处理器用户手册[S].东南大学国家专用集成电路系统工程技术研究中心,2004,06。
[3] IMP16C553 quad UART data commucications[EB/OL]. http://www.impweb.com
[4] 杜春雷.ARM体系结构与编程[M].北京:清华大学出版社,2003.
[5] 刘峥嵘,张智超,许振山,等.嵌入式Linux开发详解[M].北京:机械工业出版社,2005。
作者简介 曹 凯 男,1973年出生,硕士研究生。主要研究方向为嵌入式系统设计与应用。
凌 明 男,1972年出生,讲师。主要研究领域为嵌入式实时操作系统及相关平台。
文章评论(0条评论)
登录后参与讨论