linux上面使用ftdi芯片模拟485串口详解

                            linux上面使用ftdi芯片模拟485串口详解

一、设备信息
cpu:AR9344
switch:QCA8337
ftdi:FT4232HL
内核版本:Linux version 2.6.31--LSDK-9.2.0_U11.14

ps:我这里使用FT4232HL芯片模拟485串口的功能

FT4232HL芯片功能介绍,这些都能在ftdi官网找到相关手册

1.单芯片USB到四串行端口与各种配置。

2.整个USB协议由芯片处理,USB不需特定固件编程。

3.USB 2.0高速传输(每秒480兆位)和全速(每秒12兆位)兼容。

4.两个多协议同步串行引擎(MPSSE)的通道A和B,以简化同步串行协议(USB转JTAG,I2C,SPI 或 bit-bang)的设计。
独立的波特(baud)率发生器。

5.RS232/RS422/RS485串口传输数据速率高达12兆波特。(RS232数据速率限制由外部电平转换器决定)。

6.FTDI公司的免费虚拟COM端口(VCP)和直接(D2XX)驱动程序消除在大多数情况下的USB驱动程序开发的要求。

7.可使用TX / RX流量指示灯以添加LED和外部74HC595的移位寄存器(shift register)。

8.可调超时接收缓冲区

9.支持USB的暂停和恢复的条件,通过PWREN#,SUSPEND#和RI#引脚。

10.高度集成设计包括 +1.8V电压LDO稳压器,集成POR功能和芯片时脉倍频PLL(12MHz–480MHz)。

FTDI公司FT232B方式,异步UART串行接口选项全硬件交握和调制解调器接口信号.

完整的硬件交握或X-On/X-Off软件交握。

UART接口支持7或8位数据,1或2位停止位,和奇/偶/标志/空间/无奇偶校验。

使用TXDEN引脚做为RS485串行应用程序自动传输的启用控制。

操作配置模式和USB描述字符串通过USB接口外接EEPROM配置。

低操作和低USB暂停电流。

可配置的IO驱动强度(4,8,12或16 mA)和压摆率(slew rate)。

支持总线供电,自供电和和高功率总线供电的USB配置。

UHCI/ OHCI/ EHCI主控制器兼容。

USB批量数据传输模式(高速模式下512字节的数据包)。

专用的Windows DLL可用于USB到JTAG,USB至SPI和USB至I2C的应用。

+1.8V(芯片核心)和+3.3V的I/O接口(+5V耐压)。

扩展工业工作温度范围 -40°C 到 85°C。

简洁的64-LD无铅LQFP/LQFN封装和56-LD VQFN封装。

+ 3.3V单电源工作电压范围。

二、.调试过程
1.首先内核里面选上ftdi模块(USB_SERIAL_FTDI_SIO)
make menuconfig->kernel module->Device Drivers ->USB support->USB Serial Converter support

 

将相关的基础usb.ko以及ftdi.ko 添加进去以后,

基础的usb库
        insmod /tmp/modules/usb/usbcore.ko
        insmod /tmp/modules/usb/ehci-hcd.ko
        insmod /tmp/modules/usb/usb-storage.ko
        insmod /tmp/modules/usb/usbnet.ko
        insmod /tmp/modules/usb/cdc_encap.ko
        insmod /tmp/modules/usb/cdc_ether.ko
        insmod /tmp/modules/usb/usbserial.ko                                    
        insmod /tmp/modules/usb/option.ko


ftdi ko
        insmod /tmp/modules/usb/ftdi_sio.ko

 

设备启动以后,串口能看到识别到了ftdi芯片

usb 1-1: new high speed USB device using ath-ehci and address 2
usb 1-1: New USB device found, idVendor=0403, idProduct=6011
usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 1-1: Product: USB <-> Serial Converter
usb 1-1: SerialNumber: FT4K3SCF
usb 1-1: configuration #1 chosen from 1 choice
ftdi_sio 1-1:1.0: FTDI USB Serial Device converter detected
usb 1-1: Detected FT4232H
usb 1-1: Number of endpoints 2
usb 1-1: Endpoint 1 MaxPacketSize 2
usb 1-1: Endpoint 2 MaxPacketSize 2
usb 1-1: Setting MaxPacketSize 16384
usb 1-1: FTDI USB Serial Device converter now attached to ttyUSB0
ftdi_sio 1-1:1.1: FTDI USB Serial Device converter detected
usb 1-1: Detected FT4232H
usb 1-1: Number of endpoints 2
usb 1-1: Endpoint 1 MaxPacketSize 2
usb 1-1: Endpoint 2 MaxPacketSize 2
usb 1-1: Setting MaxPacketSize 16384
usb 1-1: FTDI USB Serial Device converter now attached to ttyUSB1
ftdi_sio 1-1:1.2: FTDI USB Serial Device converter detected
usb 1-1: Detected FT4232H
usb 1-1: Number of endpoints 2
usb 1-1: Endpoint 1 MaxPacketSize 2
usb 1-1: Endpoint 2 MaxPacketSize 2
usb 1-1: Setting MaxPacketSize 16384
usb 1-1: FTDI USB Serial Device converter now attached to ttyUSB2
ftdi_sio 1-1:1.3: FTDI USB Serial Device converter detected
usb 1-1: Detected FT4232H
usb 1-1: Number of endpoints 2
usb 1-1: Endpoint 1 MaxPacketSize 2
usb 1-1: Endpoint 2 MaxPacketSize 2
usb 1-1: Setting MaxPacketSize 16384
usb 1-1: FTDI USB Serial Device converter now attached to ttyUSB3

看到上面这些信息的话,列出来的设备ttyUSB0,ttyUSB1,ttyUSB2,ttyUSB3,就能通过串口程序打开进行读写了!

2.遇到的问题以及解决过程
第一个问题:添加了ftdi的ko以后,模拟485串口发送数据正常,无法接收数据。
通过RS232转RS485线,将电脑和设备的ttyUSB2连接起来,、
设备里面运行程序打开ttyUSB2,开启发送和接收程序,
电脑上面开启串口调试工具SSCOM或者USR-TCP232-Test.exe等
***发现设备端发送的数据,电脑上面的串口调试工具能正确收到数据*******
***电脑上面的串口调试工具发送的数据,设备端无法接收到数据************

调试过程:
一开始以为是ftdi转RS485有问题,就跳线改为ftdi直接出RS232,调试以后发现问题还是一样!这样就排除了FTDI芯片问题,

跟踪FTDI的驱动,将FTDI驱动里面接收数据函数(ftdi_process_read)添加一些打印,将收到的数据,以及数据长度打印出来,

need_flip = 0;
        for (packet_offset = priv->rx_processed;
                packet_offset < urb->actual_length; packet_offset += priv->max_packet_size) {
                int length;

                /* Compare new line status to the old one, signal if different/
                   N.B. packet may be processed more than once, but differences
                   are only processed once.  */
                char new_status = data[packet_offset + 0] &
                                                FTDI_STATUS_B0_MASK;
                if (new_status != priv->prev_status) {
                        priv->diff_status |=
                                new_status ^ priv->prev_status;
                        wake_up_interruptible(&priv->delta_msr_wait);
                        priv->prev_status = new_status;
                       
                }

                length = min_t(u32, priv->max_packet_size, urb->actual_length-packet_offset)-2; //这里发现priv->max_packet_size为2,导致length一直为0或者-1
                if (length < 0) {
                        dev_err(&port->dev, "%s - bad packet length: %d\n",
                                __func__, length+2);
                        length = 0;
                }
                if(0)
                {
                        for(i=0;i<length+2;i++)
                        {
                            dev_err(&port->dev,"data[%d]=%02x ",i,data[i]);
                        }
                       
                        dev_err(&port->dev,"length=%d\n",length);
                        dev_err(&port->dev,"max_packet_size=%d\n",priv->max_packet_size);
                        dev_err(&port->dev,"actual_length=%d\n",urb->actual_length);
                }

在源码里面查找max_packet_size,发现max_packet_size这个表示串口接收buff的长度。
有一个函数(ftdi_set_max_packet_size)是专门用来设置这个max_packet_size的

static void ftdi_set_max_packet_size(struct usb_serial_port *port)
{
        struct ftdi_private *priv = usb_get_serial_port_data(port);
        struct usb_serial *serial = port->serial;
        struct usb_device *udev = serial->dev;

        struct usb_interface *interface = serial->interface;
        struct usb_endpoint_descriptor *ep_desc = &interface->cur_altsetting->endpoint[1].desc;

      
        unsigned num_endpoints;
        int i = 0;

        num_endpoints = interface->cur_altsetting->desc.bNumEndpoints;
        dev_info(&udev->dev, "Number of endpoints %d\n", num_endpoints);

        /* NOTE: some customers have programmed FT232R/FT245R devices
         * with an endpoint size of 0 - not good.  In this case, we
         * want to override the endpoint descriptor setting and use a
         * value of 64 for wMaxPacketSize */
        for (i = 0; i < num_endpoints; i++) {
dev_info(&udev->dev, "Endpoint %d MaxPacketSize %d\n", i+1,
interface->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
ep_desc = &interface->cur_altsetting->endpoint[i].desc;
if (ep_desc->wMaxPacketSize == 0) {
      ep_desc->wMaxPacketSize = cpu_to_le16(0x40);
      dev_info(&udev->dev, "Overriding wMaxPacketSize on endpoint %d\n", i);
}
                ep_desc->wMaxPacketSize = cpu_to_le16(0x40);//*****这里将wMaxPacketSize 设置为cpu_to_le16(0x40),实际值为0x4000
        }

        /* set max packet size based on descriptor */
        priv->max_packet_size = ep_desc->wMaxPacketSize;

        dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size);
}

修改ftdi的驱动,将wMaxPacketSize 改为cpu_to_le16(0x40)以后,RS232串口接收以及发送都正常了!

第二个遇到的问题:RS232接收和发送都正常了,但是RS485发送正常,接收还是有问题(收不到数据)。
解决办法,查看FTDI的芯片手册发现,如果需要使用FTDI转RS485的话,需要添加一个eeprom来控制

第三个问题:eeprom固件编程
ftdi官方提供了一个软件FT_Prog来对eeprom编程
ps:只能通过usb将FTDI芯片跟电脑连接起来,FT_Prog才能烧写eeprom,一开始是通过手动编程器烧写eeprom的

这里选上RI as RS485 Enable就可以。

点击Program Devices按钮会将你的配置生成16进制

这里发现生成的bin文件是2k大小的!一开始我是将16进制拷贝出来,然后自己制作(使用winhex软件)一个2k的二进制文件,
然后用编程器将2k的固件烧录到1k的eeprom里面去,发现只烧录了前半部1k。

这个时候才发现对eeprom的大小也有要求,没办法只能再采购几个2k的eeprom。
等2k的eeprom到了以后,直接用编程器烧写发现RS485工作也不正常。
最后只能外接usb连接电脑,通过FT_Prog对eeprom烧写,再接上烧写好的eeprom,RS485能收到数据了,但是自己发送的数据,自己也会收到!

后续其他的eeprom烧写,将一个正常的eeprom读取出来做原始固件应该就可以了!因为接usb烧写太麻烦了!
ps:在FTDI的芯片手册里面只发现了eeprom的说明(说可用1k,2k,4k),没有强调大小。
所以后面又用1k的eeprom接usb通过FT_Prog烧写了一次。发现RS485能收到数据了,但是自己发送的数据,自己也会收到!

对比16进制的数据发现,FT_Prog程序将eeprom中间的一些没用的00去去掉了!

第四个问题:RS485会收到自己发送的数据。
解决办法:查看FT4232芯片手册发现

这里对RS485收到自己发送数据做了说明,解决办法有2个
一个是软件自己解决,后面跟其他同事讨论以后发现可行性以及稳定性不好控制,容易出错误
第二个是硬件电路控制.
最后只能等硬件工程师改好了,再验证了!

第四个问题:关于RS485串口的波特率问题。
我验证了9600,115200,以及230400,RS485接收和发送都正常。

但是波特率设置为460800以后,设备发送出来的数据,电脑上的串口调试工具收到的数据不对
电脑上串口调试工具发送的数据,设备端RS485能正常使用!!
对比了AR9344直接接出来的高速串口,现象是一样的!

####所以我不太明白,是不是硬件已经不支持了460800的波特率了,还是软件配置波特率的地方有问题!!!
目前RS485使用的波特率是只有9600和115200.所以460800波特率问题就暂时不深究了!

 

PS后续乌龙事件补充
RS485功能都正常以后,想长时间测试一些RS485的发送和接收功能。发现RS485会定时发送一些数据,当电脑收到这些异常数据以后,RS485工作就不正常了。而且一打开RS485调试,就发现RS485会先设置921600的波特率,再改为我设置好的波特率

 

后面跟踪ftdi驱动,发现发送异常数据的时候,会修改RS485的波特率为921600。
查找源码发现只有在打开RS485的时候,才会设置RS485的波特率。

这个时候就发现可能有其他程序在打开相同的RS485,去操作它!
后续跟踪发现,是自己上次做的上报GPS信息的模块引起的!
上报GPS信息的模块里面将ttyUSB2接口当成了龙尚U9300C模块生成设备,去打开,并且发送AT指令了!

windows上面打开已经被打开过串口的时候,会提示串口被占用。

linux多次打开串口(ttyUSB0),系统不会有任何提示,只能由程序员自己控制了!

***串口接口编程还是要小心一些,不能打开多次,要不然就出现我上面的乌龙事件了!

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值