基于RK3399PRo的串口驱动学习-XR21V1414IM48

目录

原理图

XR21V1414IM48简介

重点代码

函数入口初始化

tty串口操作集

USB转串初始化

设备ID

测试代码

头文件

宏定义

输入参数提示

打开设备

设置波特率

配置数据位、停止位、校验位

主函数

Makefile文件

测试代码

编译源码

执行测试程序

实验现象


原理图

由于RK3399的外设资源有限,才有了USB转串的芯片(XR21V1414IM48)。

XR21V1414IM48简介

XR21V1414IM48框架图如下所示

通过数据手册知道

  • USB Vendor ID is 0x04E2

  • USB Product ID is 0x1414

这写ID好都存在EEPROM中,通过IIC接口读取。

然后通过6组GPIOS来配置串口的属性。

在内核的源码中进行配置和初始化

在kernel/drivers/usb/serial目录中:

xr_usb_serial_common.c  //公共接口
xr_usb_serial_common.h  //公共的宏定义
xr_usb_serial_hal.c     //硬件初始化
xr_usb_serial_ioctl.h   //控制接口初始化

通过配置config进行编译和加载。

        进入arm开发板的命令终端后,可以通过lsusb命令看到USB的设备号和产品号,则证明XR这个驱动芯片识别成功。

root@linaro-alip:~# lsusb
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 006 Device 005: ID 093a:2510 Pixart Imaging, Inc. Optical Mouse
Bus 006 Device 004: ID 05e3:0608 Genesys Logic, Inc. Hub
Bus 006 Device 003: ID 04e2:1414 Exar Corp.
Bus 006 Device 002: ID 0424:2514 Standard Microsystems Corp. USB 2.0 Hub
Bus 006 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 007 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 005 Device 002: ID 0bda:d723 Realtek Semiconductor Corp.
Bus 005 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
root@linaro-alip:~#

在设备节点中可以看到初始化成功的串口。

[root@localhost ~]# ls /dev/ttyXRUSB*
ttyXRUSB0  ttyXRUSB1  ttyXRUSB2  ttyXRUSB3
[root@localhost ~]# 

重点代码

函数入口初始化

/*
 * Init / exit.
 */
static int __init xr_usb_serial_init(void)
{
        int retval;
        xr_usb_serial_tty_driver = alloc_tty_driver(XR_USB_SERIAL_TTY_MINORS);
        if (!xr_usb_serial_tty_driver)
                return -ENOMEM;
        xr_usb_serial_tty_driver->driver_name = "xr_usb_serial",
        xr_usb_serial_tty_driver->name = "ttyXRUSB",
        xr_usb_serial_tty_driver->major = XR_USB_SERIAL_TTY_MAJOR,
        xr_usb_serial_tty_driver->minor_start = 0,
        xr_usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL,
        xr_usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL,
        xr_usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
        xr_usb_serial_tty_driver->init_termios = tty_std_termios;
        xr_usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD |
                                                                HUPCL | CLOCAL;
        tty_set_operations(xr_usb_serial_tty_driver, &xr_usb_serial_ops);
​
        retval = tty_register_driver(xr_usb_serial_tty_driver);
        if (retval) {
                put_tty_driver(xr_usb_serial_tty_driver);
                return retval;
        }
​
        retval = usb_register(&xr_usb_serial_driver);
        if (retval) {
                tty_unregister_driver(xr_usb_serial_tty_driver);
                put_tty_driver(xr_usb_serial_tty_driver);
                return retval;
        }
​
        printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
​
        return 0;
}
​

tty串口操作集

/*
 * TTY driver structures.
 */
static const struct tty_operations xr_usb_serial_ops = {
        .install =              xr_usb_serial_tty_install,
        .open =                 xr_usb_serial_tty_open,
        .close =                xr_usb_serial_tty_close,
        .cleanup =              xr_usb_serial_tty_cleanup,
        .hangup =               xr_usb_serial_tty_hangup,
        .write =                xr_usb_serial_tty_write,
        .write_room =           xr_usb_serial_tty_write_room,
        .ioctl =                xr_usb_serial_tty_ioctl,
        .throttle =             xr_usb_serial_tty_throttle,
        .unthrottle =           xr_usb_serial_tty_unthrottle,
        .chars_in_buffer =      xr_usb_serial_tty_chars_in_buffer,
        .break_ctl =            xr_usb_serial_tty_break_ctl,
        .set_termios =          xr_usb_serial_tty_set_termios,
        .tiocmget =             xr_usb_serial_tty_tiocmget,
        .tiocmset =             xr_usb_serial_tty_tiocmset,
};
​

USB转串初始化

//USB转串初始化
static int xr_usb_serial_tty_install(struct tty_driver *driver, struct tty_struct *tty)
{
        struct xr_usb_serial *xr_usb_serial;
        int retval;
​
        dev_dbg(tty->dev, "%s\n", __func__);
        //添加节点
        xr_usb_serial = xr_usb_serial_get_by_index(tty->index);
        if (!xr_usb_serial)
                return -ENODEV;
        //初始化节点
        retval = tty_standard_install(driver, tty);
        if (retval)
                goto error_init_termios;
​
        tty->driver_data = xr_usb_serial;
​
        return 0;
​
error_init_termios:
        tty_port_put(&xr_usb_serial->port);
        return retval;
}

设备ID

/*
 * USB driver structure.
 */
static const struct usb_device_id xr_usb_serial_ids[] = {
        { USB_DEVICE(0x04e2, 0x1410)},
        { USB_DEVICE(0x04e2, 0x1411)},
        { USB_DEVICE(0x04e2, 0x1412)},
        { USB_DEVICE(0x04e2, 0x1414)}, //XR21V1414IM48芯片
        { USB_DEVICE(0x04e2, 0x1420)},
        { USB_DEVICE(0x04e2, 0x1421)},
        { USB_DEVICE(0x04e2, 0x1422)},
        { USB_DEVICE(0x04e2, 0x1424)},
        { USB_DEVICE(0x04e2, 0x1400)},
        { USB_DEVICE(0x04e2, 0x1401)},
        { USB_DEVICE(0x04e2, 0x1402)},
        { USB_DEVICE(0x04e2, 0x1403)},
        { }
};

测试代码

头文件

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<termios.h>
#include<errno.h>

宏定义

#define FALSE -1
#define TRUE 0
​
//串口设备名字
static char *serial_name[]={"/dev/ttyXRUSB0","/dev/ttyXRUSB1",
                        "/dev/ttyXRUSB2","/dev/ttyXRUSB3"};
int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300,B38400, B19200, B9600, B4800, B2400, B1200, B300, };
int name_arr[] = {38400,  19200,  9600,  4800,  2400,  1200,  300, 38400, 19200,  9600, 4800, 2400, 1200,  300, };

输入参数提示

//信息提示
void printf_prompt(void)
{
    printf("0:ttyXRUSB0,1:ttyXRUSB1,2:ttyXRUSB2,3:ttyXRUSB3\n");
    printf("please input the serial port for writing:");
}

打开设备

/*************************************************
*打开设备
*************************************************/
int OpenDev(char *Dev)
{
    int fd = open( Dev, O_RDWR | O_NOCTTY | O_NDELAY);         //| O_NOCTTY | O_NDELAY
    if (fd <0){ 
            perror("Can't Open Serial Port");
            exit(EXIT_FAILURE);
    }
        
    return fd;
}

设置波特率

//设置波特率
void set_speed(int fd, int speed)
{
  int   i; 
  int   status; 
  struct termios   Opt;
  tcgetattr(fd, &Opt); 
  for ( i= 0;  i < sizeof(speed_arr) / sizeof(int);  i++) 
  { 
    if  (speed == name_arr[i]) 
    {     
      tcflush(fd, TCIOFLUSH);     
      cfsetispeed(&Opt, speed_arr[i]);  
      cfsetospeed(&Opt, speed_arr[i]);   
      status = tcsetattr(fd, TCSANOW, &Opt);  
      if  (status != 0) 
      {        
        perror("tcsetattr fd1");  
        return;     
      }    
      tcflush(fd,TCIOFLUSH);   
    }  
  }
}

配置数据位、停止位、校验位

//配置参数
int set_Parity(int fd,int databits,int stopbits,int parity)
{ 
    struct termios options; 
    if  ( tcgetattr( fd,&options)  !=  0) 
    { 
        perror("SetupSerial 1");     
        return(FALSE);  
    }
    options.c_cflag &= ~CSIZE; 
    //数据位
    switch (databits) 
    {   
        case 7:     
            options.c_cflag |= CS7; 
            break;
        case 8:     
            options.c_cflag |= CS8;
            break;   
        default:    
            fprintf(stderr,"Unsupported data size\n"); 
            return (FALSE);  
    }
    //校验位
    switch (parity) 
    {   
        case 'n':
        case 'N':    
            options.c_cflag &= ~PARENB;   /* Clear parity enable */
            options.c_iflag &= ~INPCK;     /* Enable parity checking */ 
            break;  
        case 'o':   
        case 'O':     
            options.c_cflag |= (PARODD | PARENB); 
            options.c_iflag |= INPCK;             /* Disnable parity checking */ 
            break;  
        case 'e':  
        case 'E':   
            options.c_cflag |= PARENB;     /* Enable parity */    
            options.c_cflag &= ~PARODD;    
            options.c_iflag |= INPCK;       /* Disnable parity checking */
            break;
        case 'S': 
        case 's':  /*as no parity*/   
            options.c_cflag &= ~PARENB;
            options.c_cflag &= ~CSTOPB;
            break;  
        default:   
            fprintf(stderr,"Unsupported parity\n");    
            return (FALSE);  
        }  
  
    //停止位
    switch (stopbits)
    {   
        case 1:    
            options.c_cflag &= ~CSTOPB;  
            break;  
        case 2:    
            options.c_cflag |= CSTOPB;  
           break;
        default:    
             fprintf(stderr,"Unsupported stop bits\n");  
             return (FALSE); 
    } 
  
    /* Set input parity option */ 
    if (parity != 'n')   
        options.c_iflag |= INPCK; 
    
    //清空缓冲
    tcflush(fd,TCIFLUSH);
    options.c_cc[VTIME] = 150; 
    options.c_cc[VMIN] = 0; /* Update the options and do it NOW */
    if (tcsetattr(fd,TCSANOW,&options) != 0)   
    { 
        perror("SetupSerial 3");   
        return (FALSE);  
    } 
    return (TRUE);  
}

主函数

//主函数,
int main(void)
{
    int fd,i;
    //提示信息  
    printf_prompt();   
    scanf("%d",&i);
    
    //打开串口
    fd = OpenDev(serial_name[i]);  
    printf("This program updates last time at %s   %s\n",__TIME__,__DATE__);
    printf("STDIO COM1\n");
    
    //设置波特率
    set_speed(fd,115200);
    
    //设置数据位、停止位、校验位
    if (set_Parity(fd,8,1,'N') == FALSE)  {
        printf("Set Parity Error\n");
        exit (0);
    }
    //写数据
    char buf[] = "helloworld";
    write(fd,&buf,26);
    char buff[512]; 
    int nread;  
    while(1)
    {
        //读数据
        if((nread = read(fd, buff, 512))>0)
        {
            printf("\nLen: %d\n",nread);
            buff[nread+1] = '\0';
            printf("%s",buff);
            //写数据
            write(fd,&buf,26);
        }
    }
    close(fd);
    return 0;
}

Makefile文件

#---------------------------------  /* execute file(s) */
TESTFILE    = uart_test
#---------------------------------  /* object file(s) */
SRCFILE     = uart_test.c
#---------------------------------  /* header file(s) */
TESTFILE_H  =
​
CROSS = aarch64-linux-gnu-
CC = $(CROSS)gcc
AS = $(CROSS)as
LD = $(CROSS)ld
​
CFLAGS  += -O2 -Wall
​
all:   $(TESTFILE)
​
$(TESTFILE):  $(SRCFILE) $(TESTFILE_H) Makefile 
    $(CC) $(CFLAGS) -o $@ $@.c -static
    
clean:
    rm -f $(TESTFILE) *.o

测试代码

编译源码

在ubuntu中,编译测试文件

make

得到串口测试文件uart_test文件。

执行测试程序

chmod 777 uart_test
./uart_test

实验现象

串口发送的字符串,会打印出来。

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值