linux里面使用ftdi芯片模拟485并口解读

一、设备信息

cpu:AR9344

switch:QCA8337

ftdi:FT4232HL

内核版本:Linuxversion2.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暂停电流。

ftdi usb转串口驱动 linux_linux串口驱动程序_linux串口转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)

makemenuconfig->kernelmodule->DeviceDrivers->USBsupport->USBSerialConvertersupport

将相关的基础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

ftdi usb转串口驱动 linux_linux串口转usb驱动_linux串口驱动程序

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芯片问题马哥linux,

linux串口转usb驱动_linux串口驱动程序_ftdi usb转串口驱动 linux

跟踪FTDI的驱动,将FTDI驱动上面接收数据函数(ftdi_process_read)添加一些复印,将收到的数据,以及数据宽度复印下来,

need_flip = 0;
        for (packet_offset = priv->rx_processed;
                packet_offset 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 dev, "%s - bad packet length: %dn",
                                __func__, length+2);
                        length = 0;
                }
                if(0)
                {
                        for(i=0;idev,"data[%d]=x ",i,data[i]);
                        }
                       
                        dev_err(&port->dev,"length=%dn",length);
                        dev_err(&port->dev,"max_packet_size=%dn",priv->max_packet_size);
                        dev_err(&port->dev,"actual_length=%dn",urb->actual_length);
                }

在源码上面查找max_packet_sizelinux系统日志,发觉max_packet_size这个表示并口接收buff的厚度。

有一个函数(ftdi_set_max_packet_size)是专门拿来设置这个max_packet_size的

static void ftdi_set_max_packet_size(struct usb_serial_port *port)
{

ftdi usb转串口驱动 linux_linux串口转usb驱动_linux串口驱动程序

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 %dn", 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 dev, "Endpoint %d MaxPacketSize %dn", 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 %dn", 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 %dn", priv->max_packet_size); }

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

第二个遇见的问题:RS232接收和发送都正常了,而且RS485发送正常,接收还是有问题(收不到数据)。

解决办法,查看FTDI的芯片指南发觉,假如须要使用FTDI转RS485的话,须要添加一个eeprom来控制

第三个问题:eeprom固件编程

linux串口驱动程序_ftdi usb转串口驱动 linux_linux串口转usb驱动

ftdi官方提供了一个软件FT_Prog来对eeprom编程

ps:只能通过usb将FTDI芯片跟笔记本联接上去,FT_Prog能够烧录eeprom,一开始是通过自动编程器烧录eeprom的

这儿选上RIasRS485Enable就可以。

点击ProgramDevices按键会将你的配置生成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能收到数据了,而且自己发送的数据ftdi usb转串口驱动 linux,自己也会收到!

对比16补码的数据发觉,FT_Prog程序将eeprom中间的一些没用的00去除去了!

第四个问题:RS485会收到自己发送的数据。

解决办法:查看FT4232芯片指南发觉

linux串口驱动程序_ftdi usb转串口驱动 linux_linux串口转usb驱动

linux串口转usb驱动_ftdi usb转串口驱动 linux_linux串口驱动程序

这儿对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里面打开早已被打开过并口的时侯ftdi usb转串口驱动 linux,会提示并口被占用。

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

***并口插口编程还是要当心一些,不能打开多次,要不然就出现我里面的乌龙风波了!

Tagged:
Author

这篇优质的内容由TA贡献而来

刘遄

《Linux就该这么学》书籍作者,RHCA认证架构师,教育学(计算机专业硕士)。

发表回复