为您推荐:
精华内容
最热下载
问答
  • 5星
    37.73MB qq_33486907 2021-06-26 17:03:06
  • 26KB weixin_45359368 2021-07-08 13:53:54
  • 和I2C总线设备驱动一样,所有的USB驱动程序都必须创建的主要结构体是struct usb_driver,它们向USB核心代码描述了USB驱动程序,但这只是外壳,只实现了设备与总线的挂接,具体的USB设备是什么,如何实现,还需要编写...

    Linux中USB驱动程序依然遵循标准的设备驱动模型——总线、设备、驱动。和I2C总线设备驱动一样,所有的USB驱动程序都必须创建的主要结构体是struct usb_driver,它们向USB核心代码描述了USB驱动程序,但这只是外壳,只实现了设备与总线的挂接,具体的USB设备是什么,如何实现,还需要编写相应的文件操作接口。本文详细介绍USB的驱动框架。

    一. USB设备基础知识

    1.1 USB设备的配置与传输类型

    USB设备在接入系统时,以设备ID为0和主机通信,然后主机为其分配新的ID。在主机端,D+、D-都是下拉接地,设备端的D-接上拉时,表明此设备为全速设备(12Mbps),D+接上拉时为高速设备(480Mbps)。PC中的USB下拉电阻为15K,而设备中D+和D-则是1.5K上拉电阻。

    USB是主从结构,并且是树形结构,在一个USB总线上的所有设备只有一个主机。所有的传输都是由主机发起的,即USB设备没有主动通知USB主机的能力。

    USB有四种传输类型:

    控制传输:最重要的也是最复杂的传输,控制传输由三个阶段构成(初始配置阶段、可选数据阶段、状态信息步骤),每一个阶段能够看成一个的传输,也就是说控制传输其实是由三个传输构成的,用来于USB设备初次加接到主机之后,主机通过控制传输来交换信息,设备地址和读取设备的描述符,使得主机识别设备,并安装相应的驱动程式,这是每一个USB研发者都要关心的问题。

    批量传输:由OUT事务和IN事务构成,用于大容量数据传输,没有固定的传输速率,也不占用带宽,当总线忙时,USB会优先进行其他类型的数据传输,而暂时停止批量转输。例:U盘。

    中断传输:由OUT事务和IN事务构成,用于键盘、鼠标等HID设备的数据传输中;

    同步传输:由OUT事务和IN事务构成,有两个特别地方,第一,在同步传输的IN和OUT事务中是没有返回包阶段的;第二,在数据包阶段任何的数据包都为DATA0;

    USB数据的传输都是在称之为“端点”的对象之间进行的,端点0用于控制传输,可双向传输,除了端点0其他每个端点都是单向传输数据。

    OTG协议:OTG设备采用Mini-AB插座,相对于传统的USB数据线,Mini-AB接口多了一个数据线ID,ID线是否接入将Mini-AB接口区分为Mini-A和Mini-B接口两种类型。在OTG设备之间的数据连接过程中,通过OTG数据线Mini-A和Mini-B接口来确定OTG设备的主从:接入Mini-A接口的设备默认为A设备(主机接口);接Mini-B接口的设备默认为B设备(从设备)。

    1.2 USB驱动程序框架

    USB驱动程序的框架可描述如图1-1所示:

    图1-1: USB驱动架构

    一个USB设备驱动程序由一些配置、接口和端点组成。一个USB设备可以包含一个或多个配置,每个配置可包含一个或多个接口,在每个接口中可含有若干各端点。这些单元之间的关系如图1-2所示:

    图1-2: USB描述符组织结构

    二. USB驱动中的描述符

    1.1 设备描述符

    设备代表一个USB设备,由一个或多个配置组成。设备描述符用于说明设备的总体信息,并指明配置的个数,一个设备只能有一个设备描述符。

    struct usb_device_descriptor {
        __u8  bLength;			//设备描述符字节长度
        __u8  bDescriptorType;		//设备描述符类型
        
        __le16 bcdUSB;			//USB版本号
        __u8  bDeviceClass;		//接口描述符的类
        __u8  bDeviceSubClass;		//接口描述符的子类
        __u8  bDeviceProtocol;		//接口描述符的协议
        __u8  bMaxPacketSize0;		//端点0可以支持的最大包的长度
        __le16 idVendor;		//Vendor ID
        __le16 idProduct;		//Product ID
        __le16 bcdDevice;		//设备版本
        __u8  iManufacturer;		//字符串描述符生产商索引
        __u8  iProduct;		//字符串描述符产品索引
        __u8  iSerialNumber;		//字符串描述符设备串行号索引
        __u8  bNumConfigurations;	//配置编号
    } __attribute__ ((packed));

    1.2 配置描述符

    每个设备都有默认的配置描述符,支持至少一个接。配置描述符用于说明USB设备中各个配置的特性,如配置所包含的接口个数等。描述符结构定义如下:

    struct usb_config_descriptor {
        __u8  bLength;			//配置描述符长度
        __u8  bDescriptorType;		//配置描述符类型
        
        __le16 wTotalLength;		//配置返回数据的总长度
        __u8  bNumInterfaces;		//配置支持接口数目
        __u8  bConfigurationValue;	//设置配置请求值
        __u8  iConfiguration;		//描述配置的字符串描述符的索引
        __u8  bmAttributes;		//配置特性,供电选择
        __u8  bMaxPower;		//从USB总线上获取的最大电流
    } __attribute__ ((packed));

    1.3 接口描述符

    设备应该至少支持一个接口。接口时端点的集合,可以包含一个或多个可替换设置,用户能够在USB处于配置状态时改变当前接口包含的个数和特性。接口描述符结构定义如下:

    struct usb_interface_descriptor {
        __u8  bLength;			//接口描述符长度
        __u8  bDescriptorType;		//接口描述符类型
        
        __u8  bInterfaceNumber;		//接口数量
        __u8  bAlternateSetting;	//备用的接口描述符编号
        __u8  bNumEndpoints;		//该接口使用的端点数量,不包括端点0
        __u8  bInterfaceClass;		//接口类
        __u8  bInterfaceSubClass;	//接口子类
        __u8  bInterfaceProtocol;	//接口协议
        __u8  iInterface;		//描述该接口的字符串索引
    } __attribute__ ((packed));

    1.4 端点描述符

    端点是USB设备实际传输数据的对象,利用设备地址、端点号和传输方向可以指定一个端点,并与之进行通信。0号端点包含输入IN和输出OUT连个物理单元,且只支持控制传输。0号端点在设备上电后就能使用,而非0号端点必须要在配置以后才可以使用。

    根据具体应用的需要,USB设备可以包含有除0号端口以外的其它端口,对于低速设备,其附加的端点数最多为2个,对于全速、高速设备,其附加的端点最多为15个。

    struct usb_endpoint_descriptor {
        __u8  bLength;			//端点描述符长度
        __u8  bDescriptorType;		//端点描述符类型
        
        __u8  bEndpointAddress;		//端点地址:0~3位是端点编号,第7位是方向(0-OUT,1-IN)
        __u8  bmAttributes;		//端点属性:bit[1:0]的值为00-控制,01-同步,02-批量,03-中断
        __le16 wMaxPacketSize;		//本端点接收或发送的最大信息包大小
        __u8  bInterval;		//轮询数据传送端点的时间间隔
        
        /* NOTE:  these two are _only_ in audio endpoints. */
        /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
        __u8  bRefresh;
        __u8  bSynchAddress;
    } __attribute__ ((packed));

    1.5 字符串描述符

    在USB设备中通常包含字符串描述符,如制造商名称、设备序列号等。字符串描述符结构如下:

    struct usb_string_descriptor {
        __u8  bLength;			//字符串描述符长度
        __u8  bDescriptorType;		//描述符类型
        
        __le16 wData[1];		/* UTF-16LE encoded */
    } __attribute__ ((packed));

    三. 搭建驱动框架

    3.1 注册USB驱动程序

    USB设备的注册与卸载程序如下:

    static int __init usb_skel_init(void)     
    {     
        int result;     
        /* register this driver with the USB subsystem */     
        result = usb_register(&skel_driver);     
        if (result)     
            err("usb_register failed. Error number %d", result);     
       
        return result;     
    }          
    static void __exit usb_skel_exit(void)     
    {     
         /* deregister this driver with the USB subsystem */     
         usb_deregister(&skel_driver);     
    }     
        
    module_init (usb_skel_init);     
    module_exit (usb_skel_exit);     
    MODULE_LICENSE("GPL"); 

    对比I2C的设备驱动,它们非常相似。skel_driver是struct usb_driver类型结构体,我们需要实现其成员函数:

    struct usb_driver {
        const char *name;
        
        int (*probe) (struct usb_interface *intf, const struct usb_device_id *id);
        void (*disconnect) (struct usb_interface *intf);
        int (*unlocked_ioctl) (struct usb_interface *intf, unsigned int code, void *buf);
        
        int (*suspend) (struct usb_interface *intf, pm_message_t message);
        int (*resume) (struct usb_interface *intf);
        int (*reset_resume)(struct usb_interface *intf);
        
        int (*pre_reset)(struct usb_interface *intf);
        int (*post_reset)(struct usb_interface *intf);
        
        const struct usb_device_id *id_table;
        
        struct usb_dynids dynids;
        struct usbdrv_wrap drvwrap;
        unsigned int no_dynamic_id:1;
        unsigned int supports_autosuspend:1;
        unsigned int disable_hub_initiated_lpm:1;
        unsigned int soft_unbind:1;
    };

    初始化usb_driver至少需要实现五个字段:模块所有者、模块名字、probe函数、disconnect函数以及id_table。

    id_table是struct usb_device_id类型,包括一列该驱动程序可以支持的所有不同类型的USB设备。如果没有设置该变量,USB驱动程序中的探测(probe)函数将不会被调用。

    首先看看usb_device_id结构体的定义:

    struct usb_device_id {
        /* which fields to match against? */
        __u16		match_flags;
        
        /* Used for product specific matches; range is inclusive */
        __u16		idVendor;
        __u16		idProduct;
        __u16		bcdDevice_lo;
        __u16		bcdDevice_hi;
        
        /* Used for device class matches */
        __u8		bDeviceClass;
        __u8		bDeviceSubClass;
        __u8		bDeviceProtocol;
        
        /* Used for interface class matches */
        __u8		bInterfaceClass;
        __u8		bInterfaceSubClass;
        __u8		bInterfaceProtocol;
        
        /* Used for vendor-specific interface matches */
        __u8		bInterfaceNumber;
        
        /* not matched against */
        kernel_ulong_t	driver_info
        __attribute__((aligned(sizeof(kernel_ulong_t))));
    };

    USB系统通过vendor ID和Product ID的组合或者class和subclass的组合来识别设备,可以使用USB_DEVICE宏来定义这个ID:

    #define USB_DEVICE(vend, prod) \
        .match_flags = USB_DEVICE_ID_MATCH_DEVICE, \
        .idVendor = (vend), \
        .idProduct = (prod)

    例如:

    static struct usb_device_id skel_table[]={
        {USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID)},
        {}
    };
    MODULE_DEVICE_TABLE(usb, skel_table);

    MODULE_DEVICE_TABLE宏第一个参数是设备类型,第二个是设备表,这个设备表的最后一个元素是空的,用于标识结束。

    当USB设备连接到USB控制器接口时,usb_core就检测该设备的一些信息,例如生成厂商ID和产品的ID,或者是设备所属的class,subclass根protocol,以便确定应该调用哪个驱动处理该设备。

    3.2 几个重要的数据结构

    usb_skel:用于与端点进行通信,定义如下:

    struct usb_skel {
    	struct usb_device	*udev;				/* the usb device for this device */
    	struct usb_interface	*interface;			/* the interface for this device */
    	struct semaphore	limit_sem;			/* limiting the number of writes in progress */
    	struct usb_anchor	submitted;			/* in case we need to retract our submissions */
    	struct urb			*bulk_in_urb;		/* the urb to read data with */
    	unsigned char           	*bulk_in_buffer;	/* the buffer to receive data */
    	size_t				bulk_in_size;		/* the size of the receive buffer */
    	size_t				bulk_in_filled;		/* number of bytes in the buffer */
    	size_t				bulk_in_copied;		/* already copied to user space */
    	__u8				bulk_in_endpointAddr;	/* the address of the bulk in endpoint */
    	__u8				bulk_out_endpointAddr;	/* the address of the bulk out endpoint */
    	int					errors;		/* the last request tanked */
    	bool				ongoing_read;		/* a read is going on */
    	spinlock_t			err_lock;		/* lock for errors */
    	struct kref			kref;
    	struct mutex			io_mutex;		/* synchronize I/O with disconnect */
    	wait_queue_head_t	bulk_in_wait;			/* to wait for an ongoing read */
    };

    主要属性:

    描述usb设备的结构体:udev

    一个结构:interface

    用于并发访问控制的信号量:limit_sem

    用于接收数据的缓冲:bulk_in_buffer

    用于接收数据的缓冲尺寸:bulk_in_size

    批量数据端口地址:bulk_in_endpointAddr

    批量输出端口地址:bulk_out_endpointAddr

     

    usb_interface: usb接口数据结构:

    struct usb_interface {
    	struct usb_host_interface *altsetting;
    	struct usb_host_interface *cur_altsetting;	/* the currently * active alternate setting */
    	unsigned num_altsetting;	/* number of alternate settings */
    	int minor;			/* minor number this interface is * bound to */
    	enum usb_interface_condition condition;		/* state of binding */
    	unsigned sysfs_files_created:1;	/* the sysfs attributes exist */
    	unsigned ep_devs_created:1;	/* endpoint "devices" exist */
    	unsigned unregistering:1;	/* unregistration is in progress */
    	unsigned needs_remote_wakeup:1;	/* driver requires remote wakeup */
    	unsigned needs_altsetting0:1;	/* switch to altsetting 0 is pending */
    	unsigned needs_binding:1;	/* needs delayed unbind/rebind */
    	unsigned reset_running:1;
    	unsigned resetting_device:1;	/* true: bandwidth alloc after reset */
    
    	struct device dev;		/* interface specific device info */
    	struct device *usb_dev;
    	atomic_t pm_usage_cnt;		/* usage counter for autosuspend */
    	struct work_struct reset_ws;	/* for resets in atomic context */
    };

    usb_hgost_endpoint: usb端点数据结构

    struct usb_host_endpoint {
    	struct usb_endpoint_descriptor		desc;
    	struct usb_ss_ep_comp_descriptor	ss_ep_comp;
    	struct list_head		urb_list;
    	void				*hcpriv;
    	struct ep_device		*ep_dev;	/* For sysfs info */
    
    	unsigned char *extra;   /* Extra descriptors */
    	int extralen;
    	int enabled;
    	int streams;
    };

    欢迎关注亦梦云烟的微信公众号: 亦梦智能计算

     

    展开全文
    u010580016 2020-02-05 21:19:08
  • 欢迎FPGA工程师加入官方微信技术群点击蓝字关注我们FPGA之家-中国最好最大的FPGA纯工程师社群本文主要介绍Zynq UltraScale + MPSoC系列芯片的USB3.0/2.0接口硬件设计。ZU+系列MPSoC要实现USB3.0/2.0的全部功能,需要...

    欢迎FPGA工程师加入官方微信技术群

    点击蓝字关注我们FPGA之家-中国最好最大的FPGA纯工程师社群

    731c7f10323aefd999a96cfe1456bfb2.png

    本文主要介绍Zynq UltraScale + MPSoC系列芯片的USB3.0/2.0接口硬件设计。

    ZU+系列MPSoC要实现USB3.0/2.0的全部功能,需要同时使用MIO和GTR。因为GTR接口中的USB接口只支持USB3.0,对USB2.0的支持需要通过MIO接口外接USB PHY实现。

    ZU+系列MPSoC包括两个USB接口,根据实际需要可以进行如下表所示的配置:

    29ca6dffff1865628a1bfb4da8b0d816.png

    0fa196a4883848fd77ddd7bd419e4a43.png

    当USB接口配置成3.0模式时,USB2.0也必须使能(在SDK的PCW配置界面),因为外部VBUS有效的反馈信号只能从USB PHY的ULPI接口得到。在非OTG模式下,VBUS信号也可以通过PL侧信号得到,但只能通过命令的方式获得。反之,USB2.0则可以单独使用。

    MIO侧的USB2.0接口只支持ULPI接口,关于ULPI的更多信息可参考之前的文章《USB系列之“外部PHY接口”》,PHY芯片可以选择和官方开发板一样的USB3320(也可以选择其他支持ULPI接口,且接口电压为1.8V的PHY芯片)。

    337c7a68ecffdf4e4e7b7526092e0469.png

    USB3320和ZU+的连接关系如下:

    8ae18d74e01ee1e990cd8b8c7f7ad054.png

    USB3320的外部时钟输入可以配置,通过REFSEL[2..0]上下拉实现。时钟输出固定为60MHz,通过CLKOUT引脚输出,给到Link端。USB3320支持同步和异步两种传输模式,当采用同步传输时,使用SDR模式,所有的数据都是在CLK的上升沿同步传输;当采用异步模式时,CLK关闭。数据总线的方向通过DIR控制,如果两端都不驱动数据总线时,DIR的改变将产生“turn-around” cycle。

    USB3320的外部时钟配置选择如下:

    94946df92b0941e84c35b010e5dc764f.png

    USB3320的电源去耦电容、偏置电阻要求如下:

    d9984b6faf6d3d4c72a50f4509aa1c7c.png

    fb8e08eea6341c43d30ecbce7ce81c53.png

    USB3320的连接示意图如下:

    7636b17c70551442bb36fafabb2bacf7.png

    其中,ID引脚可以根据实际应用需求固定死(为高时ZU+作为DEVICE,为低时ZU+作为HOST)。

    最后,针对PCB设计,为了阻抗匹配,在设计过程中注意以下几点:

    • PCB and package delays should be kept to 1.30 ns or below.

    • PCB and package delay skews for DATA[7:0]/DIR/NXT/STP and CLK should be within ±100 ps.

    • For optimum signal integrity, add a 30Ω series resistor to the DATA and STP lines near the Zynq UltraScale+ MPSoC.(对于NXT、DIR和CLK,对于Link端是输入,不能在末端串联电阻匹配)

    以上就是针对ZU+ MPSoC的USB3.0/2.0接口的硬件设计。

    accf99c3f1817b6ef54854de55bf58d9.png

    欢迎FPGA、嵌入式、信号处理等工程师关注公众号

    ebb17e953ae3318a8010f8c8673f5658.png

    全国第一大FPGA微信技术群

    欢迎大家加入全国FPGA微信技术群,这个群体拥有数万工程师、一群热爱技术的工程师,这里的FPGA工程师相互帮助,相互分享,技术氛围浓厚!赶紧叫上小伙伴一起加入吧!

    cbce6d13e72a6662573ec24e1af64527.png

    用手指按住就可以加入FPGA全国技术群哦

    FPGA之家元器件芯城

    优势元器件服务,有需求请扫码联系群主:金娟 邮箱:293580331@qq.com 欢迎推荐给采购

    ACTEL、AD部分优势订货(经营全系列):

    f4a9d654667c4093df9eccb160b7e028.png

    XILINX、ALTERA优势现货或订货(经营全系列):

    a5fd77bd02ac20bdeae4fd952d0cb936.png

    (以上器件为部分型号,更多型号请咨询群主金娟)

    服务理念:FPGA之家元器件自营芯城,旨在方便工程师快速方便购买器件服务,经过数年竭诚服务,我们的客服遍布国内大型上市公司、军工科研单位、中小企业、最大的优势是强调服务至上的理念、并且做到快速交货、价格优惠!

    直营品牌:Xilinx ALTERA ADI TI NXP ST E2V、镁光 等百余元器件品牌,尤其擅长欧美对华禁运器件,欢迎工程师朋友把我们推荐给采购或者亲自咨询我们!我们将一如既往提供业内最佳服务!

    bab738e6ae426a1626461c061d061a98.png

    FPGA技术群官方鸣谢品牌:Xilinx、 intel(Altera)、microsemi(,Actel)、LattIC e,Vantis,Quicklogic,Lucent等

    展开全文
    weixin_39602108 2020-11-21 17:58:43
  • ZYNQ上中有USB的控制器,最近在使用pluto sdr进行数据传输的时候,觉得串口太慢,但是也没有找到关于USB的在裸机下的资料。一般都是用操作系统来做的,这就很郁闷了啊,我一个FPGA小白,现在还不会linux啊。然后就...

    前言

    在ZYNQ上中有USB的控制器,最近在使用pluto sdr进行数据传输的时候,觉得串口太慢,但是也没有找到关于USB的在裸机下的资料。一般都是用操作系统来做的,这就很郁闷了啊,我一个FPGA小白,现在还不会linux啊。然后就上GitHub上找了找看看有没有人做过zynq裸机的usb的demo,嘿,你别说,还真有。
    FPGA工程链接地址如下:
    Zynq_winUSB FPGA repo
    在这里插入图片描述
    然后还这个作者还提供了一个测试软件,C#写的,看不太懂,但是可以知道是使用libusb这个跨平台的库写的。那么之后自己在进行上位机代码编写的时候,就使用这个libusb这个库就可以了。
    上位机链接地址如下:
    usb_loop

    1. 搭建自己的USB硬件平台

    • ZYNQ板卡:微相Mizar7010
      在这里插入图片描述

    1.1 硬件平台

    使能串口,方便打印调试信息,使能USB进行USB的裸机的实验,GPIO使能一个,是因为需要使用到USB的复位信号。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    作为一个拿来主义的小白,硬件平台搭好之后,当然是直接把别人的代码拿来用了啊,简单又方便。
    在这里插入图片描述

    1.1.1 USB ID号

    在代码中有几个比较重要的文件,首先是这个USB_CONFIG.h文件,这个文件里面提供用于配置USB设备ID的信息。通过更改这个文件里面的信息,就能够将usb接入到电脑上的时候,看到更改之后的信息。
    在这里插入图片描述

    1.1.2 生成设备描述信息

    在一下两个文件当中,实现了设备信息的声明。
    在这里插入图片描述
    通过调用zynq系统的api函数,来完成设备描述文件的生成。在这里插入图片描述

    1.1.3 usb设备的初始化和中断的控制

    其实设备的初始化和中断的控制,可以直接打开vitis里面的示例demo就可以了。
    在这里插入图片描述
    设备的初始化就根据这里面来就可以。在初始化的时候,需要对usb设备进行配置。代码中配置了两个断电,一个端点用于传输控制包,一个端点用于进行块传输。
    在这里插入图片描述

    1.1.4 收发数据的API

    在代码中,原作者使用了Ringbuffer的结构来进行数据的接收发送,从这个API看来,发送和接收数据的API主要就是两个,在使用的时候,如果不去深究代码中具体干了什么事的话,使用这两个收发数据的API就可以了。
    在这里插入图片描述
    有了zynq的ps程序之后,就可以进行上位机的编写了,可以先使用上面那个作者提供的一个回环的例子,进行简单的上位机的测试,来验证一下zynq上运行的代码功能是否正确。

    2. 上位机

    上位机对于我这个不是做软件的人来说就有点麻烦了啊,不过通过查询一些资料写个简简单单的小程序应该还是可以的哈。

    2.1 使用Zadig安装驱动

    Zadig是一个开源的软件,用来给usb设备提供驱动的。使用这个软件,能够很方便地给我们地设备安装好libusb的驱动。
    首先,让vitis里面的程序运行起来,然后将usb,连接到电脑上。
    在这里插入图片描述
    这个时候,在电脑上可能会识别出一个通用串行设备。这个设备的名称,就是前面在vitis当中设置的那个名字
    在这里插入图片描述
    在这里插入图片描述
    接下来使用Zaig来给这个设备添加一个libusb的驱动。Zadig的下载地址在这里:Zadig

    • 打开软件后,先列出所有usb设备。
      在这里插入图片描述
    • 然后找到我们自己的设备,用libusb-win32给他替换一下驱动。
      在这里插入图片描述
    • 替换完成之后,在设备列表里面就能看到一个libusb的设备了
      在这里插入图片描述

    2.2 测试程序

    libusb是一个开源的跨平台的库,在github上就能够找到。有关使用方法在它的主页上有链接可以参考。下面就是驱动文件夹中自带的一个测试例子,我稍微做了点更改

    #include "stdafx.h"
    #pragma comment (lib, "libusb.lib")
    #include "lusb0_usb.h"
    #include <stdint.h>
    
    #include <Windows.h>
    #include <process.h>         // needed for _beginthread()
    
    #include <string>
    #include <iostream>
    #include <fstream>
    #include <iostream>
    #include <sstream>
    #include <string>
    using namespace std;
    
    // Enables this example to work with a device running the
    // libusb-win32 PIC Benchmark Firmware.
    //#define BENCHMARK_DEVICE
    
    //
    // TEST SETUP (User configurable)
    
    // Issues a Set configuration request
    #define TEST_SET_CONFIGURATION
    
    // Issues a claim interface request
    #define TEST_CLAIM_INTERFACE
    
    // Use the libusb-win32 async transfer functions. see
    // transfer_bulk_async() below.
    //#define TEST_ASYNC
    
    // Attempts one bulk read.
    #define TEST_BULK_READ
    
    // Attempts one bulk write.
     #define TEST_BULK_WRITE
    
    //
    // DEVICE SETUP (User configurable)
    
    // Device vendor and product id.
    #define MY_VID 0x0D7D
    #define MY_PID 0x010C
    
    // Device configuration and interface id.
    #define MY_CONFIG 1
    #define MY_INTF 0
    
    // Device endpoint(s)
    #define EP_IN 0x81
    #define EP_OUT 0x01
    
    // Device of bytes to transfer.
    #define BUF_SIZE 64
    
    //
    usb_dev_handle *open_dev(void);
    
    static int transfer_bulk_async(usb_dev_handle *dev,
    	int ep,
    	char *bytes,
    	int size,
    	int timeout);
    
    usb_dev_handle *open_dev(void)
    {
    	struct usb_bus *bus;
    	struct usb_device *dev;
    
    	for (bus = usb_get_busses(); bus; bus = bus->next)
    	{
    		for (dev = bus->devices; dev; dev = dev->next)
    		{
    			if (dev->descriptor.idVendor == MY_VID
    				&& dev->descriptor.idProduct == MY_PID)
    			{
    				return usb_open(dev);
    			}
    		}
    	}
    	return NULL;
    }
    
    int main(void)
    {
    	usb_dev_handle *dev = NULL; /* the device handle */
    	char tmp[BUF_SIZE] = "this is a test app\n";
    	int ret;
    	void* async_read_context = NULL;
    	void* async_write_context = NULL;
    
    	usb_init(); /* initialize the library */
    	usb_find_busses(); /* find all busses */
    	usb_find_devices(); /* find all connected devices */
    
    
    	if (!(dev = open_dev()))
    	{
    		printf("error opening device: \n%s\n", usb_strerror());
    		return 0;
    	}
    	else
    	{
    		printf("success: device %04X:%04X opened\n", MY_VID, MY_PID);
    	}
    
    #ifdef TEST_SET_CONFIGURATION
    	if (usb_set_configuration(dev, MY_CONFIG) < 0)
    	{
    		printf("error setting config #%d: %s\n", MY_CONFIG, usb_strerror());
    		usb_close(dev);
    		return 0;
    	}
    	else
    	{
    		printf("success: set configuration #%d\n", MY_CONFIG);
    	}
    #endif
    
    #ifdef TEST_CLAIM_INTERFACE
    	if (usb_claim_interface(dev, 0) < 0)
    	{
    		printf("error claiming interface #%d:\n%s\n", MY_INTF, usb_strerror());
    		usb_close(dev);
    		return 0;
    	}
    	else
    	{
    		printf("success: claim_interface #%d\n", MY_INTF);
    	}
    #endif
    
    #ifdef TEST_BULK_WRITE
    
    #ifdef BENCHMARK_DEVICE
    	ret = usb_control_msg(dev, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
    		14, /* set/get test */
    		2,  /* test type    */
    		MY_INTF,  /* interface id */
    		tmp, 1, 1000);
    #endif
    
    #ifdef TEST_ASYNC
    	// Running an async write test
    	ret = transfer_bulk_async(dev, EP_OUT, tmp, sizeof(tmp), 5000);
    #else
    	// Running a sync write test
    	ret = usb_bulk_write(dev, EP_OUT, "Test string \n", sizeof("Test string \n"), 5000);
    #endif
    	if (ret < 0)
    	{
    		printf("error writing:\n%s\n", usb_strerror());
    	}
    	else
    	{
    		printf("success: bulk write %d bytes\n", ret);
    	}
    #endif
    
    #ifdef TEST_BULK_READ
    
    #ifdef BENCHMARK_DEVICE
    	ret = usb_control_msg(dev, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
    		14, /* set/get test */
    		1,  /* test type    */
    		MY_INTF,  /* interface id */
    		tmp, 1, 1000);
    #endif
    
    #ifdef TEST_ASYNC
    	// Running an async read test
    	ret = transfer_bulk_async(dev, EP_IN, tmp, sizeof(tmp), 5000);
    	
    #else
    	// Running a sync read test
    	ret = usb_bulk_read(dev, EP_IN, tmp, sizeof(tmp), 5000);
    #endif
    	if (ret < 0)
    	{
    		printf("error reading:\n%s\n", usb_strerror());
    	}
    	else
    	{
    		printf("The read result is %s \n", tmp);
    		printf("success: bulk read %d bytes\n", ret);
    	}
    #endif
    
    #ifdef TEST_CLAIM_INTERFACE
    	usb_release_interface(dev, 0);
    #endif
    
    	if (dev)
    	{
    		usb_close(dev);
    	}
    	printf("Done.\n");
    
    	return 0;
    }
    
    /*
    * Read/Write using async transfer functions.
    *
    * NOTE: This function waits for the transfer to complete essentially making
    * it a sync transfer function so it only serves as an example of how one might
    * implement async transfers into thier own code.
    */
    static int transfer_bulk_async(usb_dev_handle *dev,
    	int ep,
    	char *bytes,
    	int size,
    	int timeout)
    {
    	// Each async transfer requires it's own context. A transfer
    	// context can be re-used.  When no longer needed they must be
    	// freed with usb_free_async().
    	//
    	void* async_context = NULL;
    	int ret;
    
    	// Setup the async transfer.  This only needs to be done once
    	// for multiple submit/reaps. (more below)
    	//
    	ret = usb_bulk_setup_async(dev, &async_context, ep);
    	if (ret < 0)
    	{
    		printf("error usb_bulk_setup_async:\n%s\n", usb_strerror());
    		goto Done;
    	}
    
    	// Submit this transfer.  This function returns immediately and the
    	// transfer is on it's way to the device.
    	//
    	ret = usb_submit_async(async_context, bytes, size);
    	if (ret < 0)
    	{
    		printf("error usb_submit_async:\n%s\n", usb_strerror());
    		usb_free_async(&async_context);
    		goto Done;
    	}
    
    	// Wait for the transfer to complete.  If it doesn't complete in the
    	// specified time it is cancelled.  see also usb_reap_async_nocancel().
    	//
    	ret = usb_reap_async(async_context, timeout);
    
    	// Free the context.
    	usb_free_async(&async_context);
    
    Done:
    	return ret;
    }
    

    现在就可以进行PC和ZYNQ之间的数据传输了。
    PC上运行结果:
    在这里插入图片描述
    ZYNQ上的运行结果:
    在这里插入图片描述


    参考:
    Zynq_winUSB FPGA repo

    展开全文
    qq_41332806 2020-12-30 14:14:10
  • 4KB butterf1y 2015-12-31 09:12:06
  • 通用串行总线(Universal Serial Bus)是连接计算机系统与外部...本文首先直接使用USB相关的驱动的应用,后面再具体开始编程做自己的USB驱动程序。 一.USB概要 1.1 USB的发展历程 USB1.0最早是在1996年出现,速度只...

    通用串行总线(Universal Serial Bus)是连接计算机系统与外部设备的一种串行总线标准,也是一种输入输出接口的技术规范,被广泛地应用于个人电脑和移动设备等信息通信产品。USB总线是最复杂的总线之一,但其广泛使用。本文首先直接使用USB相关的驱动的应用,后面再具体开始编程做自己的USB驱动程序。

    一.USB概要

    1.1 USB的发展历程

    USB1.0最早是在1996年出现,速度只有1.5Mb/s,后经多次发展升级,目前使用广泛的是USB2.0以及USB3.0,最新的USB3.1与USB3.2也在普及中,各版本性能如下表所示:

    USB版本

    出现年代

    传输速度

    驱动能力

    USB1.0

    1996

    1.5Mbps

    500mA

    USB1.1

    1998

    12Mbps

    500mA

    USB2.0

    2000

    480Mbps

    500mA

    USB3.0

    2008

    5Gbps

    900mA

    USB3.1

    2013

    10Gbps

    Type-A 900mA

    Type-C 100W

    1.2 电气性能

    USB2.0及以下版本采用四线通信,如图1-1所示:

    图1-1: USB电缆模型图

    其中ID数据线没有画出,只有在OTG功能中才会使用ID这个信号。USB电缆的4根线在USB接口中有固定不变的数字编号以及不同的颜色,这位电缆的识别和使用提供了方便,下表列出了这些数字和颜色规定。

    编号

    信号

    电缆颜色

    1

    Vbus

    红色

    2

    D-

    白色

    3

    D+

    绿色

    4

    GND

    黑色

    USB3.0向下兼容USB2.0所需要的Vbus,D-,D+和GND四个引脚外,还新增了两组差分导线,加上一组屏蔽线。新增的双差分线用于超速数据传输,新增的屏蔽线作为屏蔽线终端,用于处理信号中断和电子干扰。USB 3.0 Standard-A引脚分配如下:

    其中ID数据线没有画出,只有在OTG功能中才会使用ID这个信号。USB电缆的4根线在USB接口中有固定不变的数字编号以及不同的颜色,这位电缆的识别和使用提供了方便,下表列出了这些数字和颜色规定。

    编号

    信号

    电缆颜色

    1

    Vbus

    红色

    2

    D-

    白色

    3

    D+

    绿色

    4

    GND

    黑色

    USB3.0向下兼容USB2.0所需要的Vbus,D-,D+和GND四个引脚外,还新增了两组差分导线,加上一组屏蔽线。新增的双差分线用于超速数据传输,新增的屏蔽线作为屏蔽线终端,用于处理信号中断和电子干扰。USB 3.0 Standard-A引脚分配如下:

    引脚编号

    信号

    描述

    插合顺序

    1

    Vbus

    Power

    Second

    2

    D-

    USB2.0 differential pair

    Third

    3

    D+

    4

    GND

    Ground for power return

    Second

    5

    StdA_SSRX-

    Super speed receiver differential pair

    Last

    6

    StdA_SSRX+

    7

    GND_DRAIN

    Ground for signal return

    8

    StdA_SSTX-

    Super speed receiver differential pair

    9

    StdA_SSTX+

    Shell

    Shield

    Connector metal shell

    First

    二. Gadget介绍

    Linux-USB Gadget驱动框架实现了USB协议定义的设备端的软件功能。Gadget框架提出了一套标准API,在底层,USB设备控制器(USB DeviceController,UDC)驱动则实现这一套API,不同的UDC需要不同的驱动,基于API,Gadget驱动实现了一套硬件无关的功能,这基本可以对应到USB协议里的各种USB Class。

    基于底层提供的资源,Gadget驱动可以运行在各种硬件平台上。重要的驱动有:

    Gadget Zero,类似于dummyhcd,该驱动用于测试udc驱动。它会帮助您通过USB-IF测试。

    Ethernet over USB,该驱动模拟以太网网口,它支持多种运行方式:

    CDC Ethernet: usb规范规定的CommunicationsDevice Class “Ethernet Model” protocol。

    CDC Subset:对硬件要求最低的一种方式,主要是 Linux 主机支持该方式。

    RNDIS:微软公司对CDCEthernet的变种实现。

    File-backed Storage Gadget最常见的U盘功能实现。

    Serial Gadget实现,包括:

    Generic Serial实现(只需要Bulk-in/Bulk-out端点+ep0)

    CDC ACM规范实现。

    Gadget Filesystem,将GadgetAPI接口暴露给应用层,以便在应用层实现user modedriver。

    MIDI: 暴露ALSA接口,提供recording以及playback功能。

    三. USB虚拟串口

    ZYNQ7000中有两个USB外设,它们都可以当做OTG功能使用,为了使其变成可以虚拟串口或U盘等USB从设备,需要将USB配置为从设备。

    1.1 配置内核

    Linux内核提供了Gadget模块,该模块提供了USB的许多通用功能,包括虚拟串口,大容量存储设备等功能。在内核编译时配置其为编译成模块。

    在内核文件路径下make menuconfig后,配置选项:

    Device Drivers --->
    [*]USB support --->
        [*]USB Gadget Support --->
            [M]USB Gadget Drivers
                ...
                [M]Serial Gadget(with CDC ACM and CDC OBEX support)

    保存退出后,编译内核,在/drivers/usb/gadget目录下会生成以下驱动文件:

    g_serial.ko, libcomposite.ko, usb_f_acm.ko, usb_f_obex.ko, usb_f_serial.ko, u_serial.ko.

    配置设备树,设置USB0为从设备模式,将原来的dr_mode="host"更改为:

    dr_mode="peripheral":
    &usb0 {
    	status = "okay";
    	dr_mode = "peripheral";
    	phy_type = "ulpi";	
    };

    生成新的设备树devicetree.dtb文件。

    1.2 加载模块并测试

    将编译好的内核,设备树文件放入SD卡,并启动Linux,按顺序加载前面生成的驱动模块:

    Z-turn# insmod u_serial.ko
    Z-turn# insmod libcomposite.ko
    Z-turn# insmod usb_f_serial.ko
    Z-turn# insmod usb_f_obex.ko
    Z-turn# insmod usb_f_acm.ko
    Z-turn# insmod g_serial.ko
    g_serial gadget: Gadget Serial v2.4
    g_serial gadget: g_serial ready
    zynq-udc: bind to driver g_serial
    Z-turn# g_serial gadget: high-speed config #2: CDC ACM config
    g_serial gadget: high-speed config #2: CDC ACM config

    输出上述信息表示加载模块成功。此时打开设备文件发现多了/dev/ttyGS0设备,这个就是虚拟的串口设备。连接USB数据线到电脑,发现设备管理器中增加了一个串口设备(ELMO GMAS(COM14))。WIN7和WIN10会自动加载基于udc标准的串口驱动,即免驱。

    打开串口调试助手,在ZYNQ终端中输入发送测试命令:

    Z-turn# echo hello > /dev/ttyGS0

    在串口调试助手中可以收到hello\r\n

    在ZYNQ终端输入串口接收命令:

    Z-turn# cat /dev/ttyGS0

    在串口调试助手中输入:hello\n,则ZYNQ终端中可以收到hello。

    注:在终端中发送与接收串口数据都是以'\n'为终止条件,即发送的数据会追加'\n',接收的数据必须在收到'\n'时回显。

    四. USB虚拟U盘

    在调试Linux系统时,我们经常需要修改SD卡中的文件,更新文件系统或者Linux内核、设备树等文件,需要实现通过USB数据线与PC连接,作为PC的存储设备,PC可以直接拷贝文件到开发板中,或者把开发板中的文件通过USB数据线拷贝到PC端,实现数据交互。本文办卡采用Linux3.15内核,ZYNQ7010处理器。

    1.1 配置内核

    在内核文件路径下make menuconfig后,配置选项:

    Device Drivers --->
    [*]USB support --->
        [*]USB Gadget Support --->
            [M]USB Gadget Drivers
                ...
                [M]Gadget Filesystem
                [M]Mass Storage Gadget

    编译内核后,在/drivers/usb/gadget中生成了g_mass_storage.ko文件,把这个文件复制到开发板中。

    1.2 PC识别开发板的SD卡

    在嵌入式Linux系统中,SD卡在系统中识别为/dev/mmcblk0,如果有多个分区则每个分区分别是/dev/mmcblk0p1,/dev/mmcblk0p2等,将SD卡目录挂载到PC中进行读写的方法如下:

    在终端中执行命令:

    Z-turn# modprobe g_mass_storage file=/dev/mmcblk0 removable=1

    该命令加载了gadget msc驱动,传递SD卡位模块参数。连接USB数据线到PC,这时在PC端识别了SD卡所有分区,FAT32格式的分区可以显示内容,对于SD卡的ext4,ext3等文件系统无法在windows中显示,只显示一个盘符。此时可以通过USB数据线读写SD卡了。

    如果只需要挂载一个分区,修改file参数即可:

    Z-turn# modprobe g_mass_storage file=/dev/mmcblk0p1 removable=1

    1.3 PC识别开发板的内存文件系统(Ramdisk)

    首先创建一个50M的内存文件:

    Z-turn# dd if=/dev/zero of=/dev/50M bs=1M count=50

    加载Gadget相关的模块:

    Z-turn# modprobe g_mass_storage file=/dev/50M removable=1

    加载模块后在windows中弹出是否格式化新增的盘符,格式化为FAT格式,往该盘符中添加文件,在Linux中将/dev/50M挂载到/mnt目录下,查看/mnt目录可以发现添加的文件在其中。

    图1-1: PC识别Linux中文件为U盘

    需要注意的是,该文件系统是RAMDISK文件系统,系统重启后所有的数据内容会丢失。

    三. 使用USB共享网络

    使用USB来共享网络可以不需要连接路由器,减少开发设备。

    配置内核:

    Device Drivers --->
    [*]USB support --->
        [*]USB Gadget Support --->
            [M]USB Gadget Drivers
                ...
                [M]Ethernet Gadget(with CDC Ethernet support)
                [*]  RNDIS support

    如下图所示:

    图3-1: 配置RNDIS共享USB网络

    还需要配置RNDIS模块,其位于:

    Device Driver--->
        Network device support
            USB Network Adapters
                [*]Multi-purpose USB Networking Framework
                    <M>HOST for RNDIS and ActiveSync devices

    编译内核后,rndis_hos.ko的路径为/drivers/net/usb/rndis_host.ko


    欢迎关注亦梦云烟的微信公众号: 亦梦智能计算

     

    展开全文
    u010580016 2020-02-05 20:59:12
  • Zhu_Zhu_2009 2018-10-06 21:45:23
  • Zhu_Zhu_2009 2019-08-25 20:31:28
  • 1.06MB qq_25648927 2019-08-09 10:16:25
  • weixin_39193953 2020-08-22 16:47:53
  • xfxiaofan123456 2017-08-11 20:00:55
  • 38.66MB zhaocy2012 2020-05-04 00:51:28
  • weixin_45786595 2021-11-04 22:34:41
  • liuheda 2016-10-07 17:17:22
  • qq84395064 2018-03-28 11:27:29
  • m0_37535642 2017-02-15 07:43:46
  • MmikerR 2020-06-02 16:07:07
  • wrong_jian 2020-01-07 17:57:37
  • 106B weixin_42189611 2021-03-05 15:17:20
  • qq_26849933 2021-04-30 16:10:21
  • u014689277 2021-07-21 11:19:46
  • weixin_39876450 2021-05-17 22:41:24
  • feitingfj 2020-09-20 15:15:28
  • 319KB robotblog 2021-08-04 04:44:09
  • 4.16MB weixin_42679995 2021-10-04 12:54:20
  • weixin_42078819 2020-05-12 14:29:29
  • weiaipan1314 2020-12-27 09:49:08
  • qq_25648927 2019-08-09 10:13:20

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,848
精华内容 739
关键字:

usbzynq