找回密码
 注册会员
更新自动建库工具PCB Footprint Expert 2024.04 Pro / Library Expert 破解版

[嵌入式/ARM] 基于华邦W90P710的嵌入式Linux串口驱动的实现方法

[复制链接]
admin 发表于 2013-3-24 17:54:55 | 显示全部楼层 |阅读模式

本文包含原理图、PCB、源代码、封装库、中英文PDF等资源

您需要 登录 才可以下载或查看,没有账号?注册会员

×
摘  要: 基于华邦W90P710处理器的Linux内核应用,详细介绍了Linux串口驱动的实现方法。同时对Linux文件系统操作入口函数及内核的编译做了详细的说明。
关键词: ARM;Linux;UART;文件系统;串口驱动程序
   嵌入式Linux是一种很受欢迎的操作系统,具有开放源码、不存在黑箱技术、内核小、功能强大、运行稳定、效率高、易于定制裁减等特点[1],广泛应用于工控产品。很多工控产品需要和外部设备进行信息交换,而串口通信是最简单快捷的实现方法。在不同的工控产品中,由于对所选用的串口元件或者串口通信的数据格式、波特率等有不同的需求,需要对串口驱动进行开发。华邦W90P710采用ARM的ARM7TDMI微处理器核心,采用?滋CLinux-2.4.20内核,支持4组通用异步接收发送口(UART),下面基于华邦W90P710的串口驱动详细分析串口驱动的实现方法,实现嵌入式设备通过串口对外通信。
1 华邦W90P710 UART介绍
     华邦W90P710支持4组UART,串口的控制主要通过以下寄存器实现[2]:
     (1)行寄存器(UART_LCR):设置数据位长度、奇偶校验、停止位数。
     (2)波特率除数寄存器(UART_DLL、UART_DLM):波特率发生器的公式为:BaudOut=crystal clock/16×[Divisor +2],Divisor为当前波特率。
     (3)Modem控制寄存器(UART_MCR):控制RTS、CTS等信号。
     (4)FIFO控制寄存器(UART_FCR):设置FIFO的长度,复位FIFO等控制。
     (5)接收超时寄存器(UART_TOR):收到首个字节后接收器启动本超时,之后每收到一个字节后都会重置该值,在此超时时间内不再收到数据时,接收器会产生一个接收中断。
     (6)中断控制器(UART_IER):设置接收、发送、行中断等。
     在使用RXDn、TXDn前必须对GPIO进行配置,使能RXDn、TXDn,串口才可正常运行。GPIO配置对应表如表1所示。
    20121107050710363794013.gif
   2 Linux系统驱动介绍
     设备驱动程序是操作系统内核和机器硬件之间的接口。设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,应用程序可以像操作普通文件一样对硬件设备进行操作。同时,设备驱动程序是内核的一部分[3]。图1所示为设备驱动程序接口流程图。
    20121107050710410674014.gif
       Linux系统的设备分为字符设备、块设备和网络设备三种。字符设备是指存取时没有缓存的设备,只能顺序读写。典型的字符设备包括鼠标、键盘、串行口等;块设备一般都有缓存来支持,并且块设备必须能够支持随机存取。块设备主要包括硬盘设备、CD-ROM等;网络设备在Linux系统中用做专门的处理,Linux的网络系统主要是基于BSD Unix的socket机制[4]。
3 串口驱动程序详细介绍
     一般来说,Linux的设备驱动程序包括驱动程序的注册和注销、设备的打开和释放、设备的读写操作、设备的控制操作、设备的中断和轮询处理等功能。下面就这些功能对串口驱动进行详细说明。
     (1)串口设备的数据结构包括串口参数接收发送缓冲区等。串口参数包括波特率、数据位、数据起始位、奇偶校验、串口类型、发送缓冲区、接收缓冲区等,每个串口对应一个如下的数据结构:
     typedef struct{
         int  bps;
         int  databits;
         int  stopbits;
         int  parity;
         int  siotype;        //串口参数
         int  openflag;
         int  recvTrigTimeout;
         SIO_D_SEND_BUFFER    *pSendBuf;//发送缓冲区
         SIO_D_RECV_BUFFER    *pRecvBuf;//接收缓冲区
         struct fasync_struct *fasync_queue;
         wait_queue_head_t    read_wait;
     }serial_dev;
     static serial_dev serial_device;
     (2)文件系统操作入口函数对应文件操作函数read ()、write()、ioctl()、open()、close()。
     struct file_operations serial_fops = {
         owner:        THIS_MODULE,
         poll:            serial_poll,
         read:        serial_read,
         write:        serial_write,
         ioctl:        serial_ioctl,
         open:        serial_open,
         release:    serial_release,
     };
     (3)驱动程序注册和注销。驱动程序在应用前,需要在模块初始化时将设备注册到系统设备表中;不再使用时,将设备从系统中卸除。注册包括初始化定时器、初始化串口数据结构serial_device和字符设备注册。注销时直接调用设备注销函数[5]。
     int __init topbandserial1_init(void)
     {
         init_timer(&timer);//初始化定时器结构
         memset(&serial_device, 0, sizeof(serial_device));
         result=register_chrdev(SERIAL1_MAJOR, "serial1",
&serial_fops);
         …
     }
     (4)串口设备打开包括分配串口的接收发送缓冲区及中断注册[5]。
     static int serial_open(struct inode *inode, struct file *filp)
     {
       dev->pRecvBuf = kmalloc(sizeof(SIO_D_RECV_BUFFER), GFP_KERNEL);
       request_irq(INT_UART1,serial_interrupt,SA_SHIRQ,
"TopbandSerial1",&serial_device);
       …
     }
     (5)串口设备释放包括释放内存空间、注销中断和删除定时器[5]。
     static int serial_release(struct inode *inode, struct file *flip)
     {
         serial_dev *dev = flip->private_data;//释放内存空间
         kfree(dev->fasync_queue);
         CSR_WRITE(COM_IER_1, 0x00); /* 中断禁止 */
         free_irq(INT_UART1, dev); //注销中断
         del_timer(&timer);//删除定时器
         MOD_DEC_USE_COUNT;
         dev->openflag = 0;
         …
     }
     (6)串口读数据是指返回接收缓冲区中已收到的数据。读取数据有两种方式,阻塞方式和非阻塞方式。阻塞方式[6]中用户程序执行读操作时如果没有数据可读,即让read()操作等待直到数据可读;非阻塞方式中当用户执行读操作时,不论串口是否接收到数据,设备驱动xxx_read()函数会立刻返回,read()函数系统调用也随即返回。
     static int serial_read(struct file *filp, char *buf, size_t
count, loff_t *f_pos)
     {
             if(filp->f_flags & O_NONBLOCK)/非阻塞方式读取
             retsts = serial_nonblock_read(dev,buf,count);
         else    /*阻塞方式读取*/
             retsts = serial_block_read(dev,buf,count);   
         …
     }
     (7)串口写数据包括把数据存放在发送缓冲区、启动硬件发送及发送中断。当发送第一个字节后,硬件会产生发送中断,剩下的数据将在中断处理程序中发送。
     static int serial_write(struct file *filp, const char *buf,
size_t count, loff_t *f_pos)
     {
     copy_from_user(&pSendBuf->frameData[pSendBuf->
bufWritex].data[0],buf, count);
         CSR_WRITE(CMBOARD_GPIO_DATAOUT1,status1);
     enable_tx_interrupt_1();
         …
     }
     (8)串口控制包括设置串口波特率、奇偶校、停止位等,还可以定义其他特殊的控制。应用程序通过ioctl()调用把串口的参数传递给驱动程序,驱动程序再通过对硬件串口控制寄存器进行设置,来满足应用层用户要求。
     static int serial_ioctl(struct inode *inode, struct file *flip,
unsigned int cmd, unsigned long arg)
     {
         switch(cmd){
                 case SERIAL_IOC_BPS:
                     …
                     break;
                 case SERIAL_IOC_SENDBUF:
                     …
                     break;
             }
     }
     (9)中断处理包括对接收中断、发送中断、异常中断的处理。读取中断寄存器的状态,根据不同的中断类型分别处理。当收到数据时,硬件会产生接收中断,驱动程序把串口的数据读取出来,放在接收缓冲区中,直到所有数据读取完成;当发送数据时,硬件会产生发送中断,驱动程序把发送缓冲区的数据发送出去,直到所有数据发送完成;当串口接收或发送发生异常时,会产生异常中断,驱动程序根据情况把串口重新初始化,以便串口恢复正常。
     static void serial_interrupt(int irq, void * dev_id,
struct pt_regs *regs)
     {
         status = CSR_READ(COM_IIR_1);
         while(status & UART_IIR_STATUS_NO) == 0)
         {
             switch(status)
             {
                 case UART_IIR_STATUS_RDA:
                  case UART_IIR_STATUS_TOUT:
                      receive_chars(dev,status);
                      break;
                  case UART_IIR_THRE:   
                      transmit_chars(dev);
                      break;
              }
              status = CSR_READ(COM_IIR_1);
          }
  }
     (10)定时器处理。中断接收程序只负责把数据读取到缓冲区,并没有指示缓冲区的数据可被用户使用,这时需要在超时程序中把可用标志置上,当用户调用read()函数时就可把接收缓冲区的数据返回。
     static void serial_timer(unsigned long dummy)
     {
         …
         serial_device.pRecvBuf->frameData
[serial_device.pRecvBuf->bufWritex].finished = 1;
         mod_timer(&timer,jiffies+2);/* 20 ms 进一次 */
     }
*滑块验证:
您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

QQ|手机版|MCU资讯论坛 ( 京ICP备18035221号-2 )|网站地图

GMT+8, 2024-12-26 11:51 , Processed in 0.057900 second(s), 10 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表