[原创] LPC1114/LPC11U14和LPC1343对比学习(八)USB

zhaojun_xf   2011-9-18 08:28 楼主

          这3种芯片的功能非常多,到此基本上我们已经介绍完成,只有AD、WDT等没有介绍,鉴于其难度不大这方面的内容就不再说明。下面将进行终极篇的学习----USB学习,由于USB难度非常大,这一贴可能会编写很长时间,这里将主要学习HID的应用。。。

 

          LPC1114没有USB功能,所以这里只能针对LPC1343和LPC11U14进行说明。对于这两种有USB功能的芯片其还是区别,LPC1343内部集成了USB驱动,而LPC11U14没有此功能,所以LPC1343USB开发比较简单一点,价格也要贵一点。为了编写出通用的USB驱动代码,这里将先对LPC11U14 USB进行学习,之后在移植到LPC1343。

 

         鉴于USB开发难度,这里将不会从零开始开发USB驱动,我们将对NXP设计的USB驱动进行学习,并改进成一个自定义的HID,应用在自己的项目中。。。

 

 

USB HID源代码,增加了注释,并且都整理过,不可多得啊

USB HID(NXP原厂代码).rar (31.85 KB)
(下载次数: 41, 2011-10-9 21:42 上传)

[ 本帖最后由 zhaojun_xf 于 2011-10-9 21:45 编辑 ]
我的博客

回复评论 (18)

对于USB的硬件设计非常简单,具体设计如下图所示:

1.jpg

 

1. 除了连接好USB的两路差分信号线外,还必须连接好电源,对于P0_3是非常重要,不管是否使用USB电源供电,此管脚必须接高电平,否则无法设别USB设备。而且,如果要应用USB ISP功能,此管脚也必须接高电平。

 

2. P0_6管脚为软件连接端口,可以通过此管脚连接或断开USB设备。

 

3. 全速和高速设备的上拉电阻接在D+端,而低速设备是接在D-端的。

 

4. USB设备取电:在设备没有配置之前最多只能从Vbus上获取100mA电流,电流的大小是由设备配置的,配置后最多可获取500mA电流。

[ 本帖最后由 zhaojun_xf 于 2011-9-18 08:57 编辑 ]
我的博客
点赞  2011-9-18 08:40

USB基础知识:

 

1. 在USB1.0和USB1.1中只支持1.5M/s的低速模式和12M/s的全速模式,在USB2.0中又加入了480M/b的高速模式,而在USB3.0中速度到达5GB/s。

 

2. USB集成器只能扩展USB接口,而能扩展带宽,一个主控制器的带宽是固定的。

 

3. 在USB1.1中集成器最多4层,USB2.0中最多6层。

 

4. 低速和全速模式下采用电压差分传输信号,在高速模式下,采用电流传输。

 

5. USB采用NRZI编码方式,0数据电平翻转,1数据电平不翻转。

我的博客
点赞  2011-9-18 09:05

USB的描述符应该是USB开发主重要的部分,如果能够正确的配置好描述符,USB开发就完成了一半了。

 

描述符:

 

对于HID设备的描述除了5个USB的标准描述:设备描述符、配置描述符、接口描述符、端点描述符、字符串描述符。

 

HID设备还有3个特点描述符:HID描述符、报告描述符、实体描述符。

 

在5个标准描述符中与HID设备有关的部分有:

 

1. 设备描述符中bDeviceClass、bDeviceSubClass、bDeviceProtocol三个字段的值必须为零。

 

2. 接口描述符中bInterfaceClass的值必须为0x03,bInterfaceSubClass的值为1时表示Boot Device,即表示HID是一个启动设备。

 

上面的描述符之间有一定的关系,一个设备只有一个设备描述符,而一个设备描述符可以包含多个配置描述符,而一个配置描述符可以包含多个接口描述符,一个接口使用了几个端点,就有几个端点描述符。这间描述符是用一定的字段构成的,分别如下说明:

1、 设备描述符

struct _DEVICE_DESCRIPTOR_STRUCT
{

BYTE bLength;                 // 设备描述符的字节数大小,为0x12
BYTE bDescriptorType;         // 描述符类型编号,为0x01
WORD bcdUSB;                  // USB版本号
BYTE bDeviceClass;            // USB分配的设备类代码,0x01~0xfe为标准设备类,

// 0xff为厂商自定义类型
                              // 0x00不是在设备描述符中定义的,如HID
BYTE bDeviceSubClass;         // usb分配的子类代码,同上,值由USB规定和分配的
BYTE bDeviceProtocl;          // USB分配的设备协议代码,同上
BYTE bMaxPacketSize0;         // 端点0的最大包的大小
WORD idVendor;                // 厂商编号
WORD idProduct;               // 产品编号
WORD bcdDevice;               // 设备出厂编号
BYTE iManufacturer;           // 描述厂商字符串的索引
BYTE iProduct;                // 描述产品字符串的索引
BYTE iSerialNumber;           // 描述设备序列号字符串的索引
BYTE bNumConfiguration;       // 可能的配置数量

}

2、配置描述符
struct _CONFIGURATION_DESCRIPTOR_STRUCT
{

BYTE bLength;               // 设备描述符的字节数大小,为0x12
BYTE bDescriptorType;       // 描述符类型编号,为0x01
WORD wTotalLength;          // 配置所返回的所有数量的大小
BYTE bNumInterface;         // 此配置所支持的接口数量
BYTE bConfigurationVale;    // Set_Configuration命令需要的参数值
BYTE iConfiguration;        // 描述该配置的字符串的索引值
BYTE bmAttribute;           // 供电模式的选择
BYTE MaxPower;              // 设备从总线提取的最大电流

}

3、字符描述符

struct _STRING_DESCRIPTOR_STRUCT
{

BYTE bLength;               // 设备描述符的字节数大小,为0x12
BYTE bDescriptorType;       // 描述符类型编号,为0x01
BYTE SomeDescriptor[36];    // UNICODE编码的字符串

}

4、接口描述符
struct _INTERFACE_DESCRIPTOR_STRUCT
{

BYTE bLength;               // 设备描述符的字节数大小,为0x12
BYTE bDescriptorType;       // 描述符类型编号,为0x01
BYTE bInterfaceNunber;      // 接口的编号
BYTE bAlternateSetting;     // 备用的接口描述符编号
BYTE bNumEndpoints;         // 该接口使用端点数,不包括端点0
BYTE bInterfaceClass;       // 接口类型
BYTE bInterfaceSubClass;    // 接口子类型
BYTE bInterfaceProtocol;    // 接口所遵循的协议
BYTE iInterface;            // 描述该接口的字符串索引值

}

5、端点描述符
struct _ENDPOIN_DESCRIPTOR_STRUCT
{

BYTE bLength;               // 设备描述符的字节数大小,为0x12
BYTE bDescriptorType;       // 描述符类型编号,为0x01
BYTE bEndpointAddress;      // 端点地址及输入输出属性
BYTE bmAttribute;           // 端点的传输类型属性
WORD wMaxPacketSize;        // 端点收、发的最大包的大小
BYTE bInterval;             // 主机查询端点的时间间隔

}

 

1.JPG

 

报表描述符

报表描述符定义了执行设备功能的数据格式和使用方法。

报表描述符和USB的其他描述符是不一样的,它不是一个简单的表格,报表描述符是USB所有描述符中最复杂的。报表描述符非常复杂而有弹性,因为它需要处理各种用途的设备。报表的数据必须以简洁的格式来储存,这样才不会浪费设备内的储存空间以及数据传输时的总线时间。

实际上可以这样理解,报表内容的简洁,是通过报表描述符全面的、复杂的数据描述实现的。

报表描述符必须先描述数据的大小与内容。报表描述符的内容与大小因设备的不同而不同,在进行报表传输之前,主机必须先请求设备的报表描述符,只有得到了报表描述符才可正确解析报表的数据。

报表描述符是报表描述项目(Item)的集合,每一个描述项目都有相对统一的数据结构,项目很多,通过编码实现。

 

在HID的8种描述符中,最为重要而且复杂的应该是报表描述符,其定义了数据的存储格式和实际意义。如果能够正确的理解报表描述符,那么对数据的处理就能达到应用自如了,所以在设计描述符的时候,一定好多话费时间来理解和编写这一部分的内容。特别要主要以下几点:

1. 输入输出等项使用的数据必须是整数字节,如果没有完全使用到,也必须通过说明来补齐。

2.主要报表的三种项的应用及使用范围。

 

2.JPG

 

命令请求:

 

HID设备类特定的命令有6个:Get_Report、Get_Idle、Get_Protocol、Set_Report、Set_Idle、Set_Protocol。

[ 本帖最后由 zhaojun_xf 于 2011-9-20 07:51 编辑 ]
我的博客
点赞  2011-9-18 09:24

通过近段时间来对NXP的HID例程的学习,对其有了个大致的了解,USB一个包含以下几个文件:

 

1.JPG

 

1. hid.h文件对HID协议中使用到的各种描述符、字段等进行了全面的描述和定义,在需要更改其他应用时,只需要选择相应的宏就可以,非常清晰明确。

 

2.hiduser.c/hiduser.h文件对HID中需要使用到的6中设备命令请求函数进行了编写描述。

 

3.usb.h文件对USB标准中需要使用的报告和描述符进行全面的定义。

 

4.usbcfg.h文件对USB中应用到的电源、端点、接口、缓冲等进行配置说明,完全可以根据自己的需要来配置USB。

 

5.usbcore.c/usbcore.h文件是USB协议内核文件,是各种USB开发必备文件,完成了USB的核心内容,也是USB开发的难点和重点。

 

6.usbdesc.c/usbdesc.h文件为USB各种描述符的实现代码,开发不同的HID设备时,需要在此文件中更改相应描述。

 

7.usbhw.c/usbhw.h文件实现与USB相关的硬件配置等。

 

8.usbuser.c/usbuser.h文件实现各种事件和端点的实现代码,根据自己的应用更改端点代码实现USB通信。

[ 本帖最后由 zhaojun_xf 于 2011-9-26 08:22 编辑 ]
我的博客
点赞  2011-9-18 09:49

在HID开发中,报告描述符是最关键而且最复杂的描述符,因为它没有专门的格式,随意性比较大,但是HID的数据解析完全是依靠此描述符。

 

下面是NXP例程中的HID的报告描述符:

 

1.jpg

 

程序代码都注释了,这里不再详细说明,需要注意中间三段代码:

 

1. 第一段中定义了一个Input,数据为1位,一共有3个这样是数据;

 

2. 第二段中定义了一个Input,数据为1位,一共有5个这样是数据,不过需要注意,这里定义的是常量。就是说这里的5个位并没用实际意义,完全是为了补齐一个字节的。这一点要注意,在报告描述符中,必须使用整数字节

 

3. 第三段中定义了一个Output,数据为1位,一共有8个这样的数据,也就是说,由8个位组成的一字节输出数。

 

       到此我们不难看出此HID使用的是1字节是输入和1字节是输出,只是在1字节输入数据中,这里只使用了3为。对于其他的描述符这里就不再说明,可以直接对照上面的描述符格式就可以看懂,需要注意HID必须设置的几个字段就行了。

 

[ 本帖最后由 zhaojun_xf 于 2011-9-27 07:34 编辑 ]
我的博客
点赞  2011-9-18 09:49

其他描述符:

 

1.JPG

 

3.JPG

 

2.JPG

 

 

 

在这些描述符中我们可以看出设备的具体功能,以及通信使用的端点,缓存等

[ 本帖最后由 zhaojun_xf 于 2011-9-27 07:42 编辑 ]
我的博客
点赞  2011-9-18 09:49

通过上述对描述符的了解,基本的HID信息我们已经了解,下面就可以编写程序,通过把获取的数据进行验证了,这里我们是通过按键按下给PC发送数据,通过PC发送数据在设备上通过LED显示的。

 

4.JPG

 

5.JPG

[ 本帖最后由 zhaojun_xf 于 2011-9-27 07:45 编辑 ]
我的博客
点赞  2011-9-18 09:49

到此就可以把代码下载到开发板上,并通过实验进行验证了。下面我们采取两种方法:

 

1.使用周工例程中的HID Client上位机软件,进行验证。

 

    把开发板下载代码后插入PC,通过Device选择我们的“LPC11Uxx USB HID”设备,下面我们可以看出,设备在没有键按下时读取为0x01,当按下键时,读取为0x00。在Outputs中勾选相应的复选框,我们可以看到开发板上相应的LED就别点亮了。

 

    这种方法只是验证本实验是可以的,但是要开发其他USB功能设备就不行了,下面我们介绍一种通用的方法。

 

3.jpg

 

2. 使用Bus Hound软件验证,这个软件,刚开始很多人都不会用,这里将详细点。

 

打开软件,在设备项选择我们的USB设备,如下图

 

1.JPG

 

需要注意的是在发送数据时,需要选择USB人体学输入设备,而不是下面的HID-compliant device。如果是双击HID-compliant device弹出的窗口中并没有端点,是不能通信的,应该双击USB人体学输入设备,弹出如下界面:

 

2.JPG

 

通过上图,我们可以看出,端点和我们定义的是一样的

 

下面我们就可以选择端点进行数据通信了,选择需要端点,填写发送数据长度,在下面输入要发送的数据,选择“Run”,就可以把数据发送出去了。

之后把软件切换到Capture,可以捕获输入输出数据,如下图。

 

2.jpg

 

通过上面的验证,我们可以得知,实验结果和我们想要的是一样的,以后对于多字节的收发,我们就可以通过Bus Hound软件进行验证了。

[ 本帖最后由 zhaojun_xf 于 2011-9-27 08:05 编辑 ]
我的博客
点赞  2011-9-18 09:49

通过上面的简单介绍,我们对HID有了一定的认识,下面我们可以根据需要把NXP的例程更改成我们实际需要的HID设备,进行进一步学习了。。。

 

本贴NXP HID具体例程代码如下(周工代码,里边有HIDClient软件):

USBHID.rar (184.26 KB)
(下载次数: 99, 2011-9-27 21:47 上传)

[ 本帖最后由 zhaojun_xf 于 2011-9-27 21:49 编辑 ]
我的博客
点赞  2011-9-18 09:49

自定义多字节发送的实现:

 

下面我们只需要修改几个部分就能实现了。

 

1. 修改报告描述符:

 

1.jpg

 

2. 修改端点描述符:

 

2.jpg

 

3. 修改输入输出变量:

 

3.jpg

 

4. 修改其他与InReport和OutReport相关的地方。

 

5. 编写代码实现接收后原样返回。

 

6. 试验一下:

 

4.jpg

[ 本帖最后由 zhaojun_xf 于 2011-9-27 22:06 编辑 ]
我的博客
点赞  2011-9-27 22:04
支持下楼主的精彩讲解,我手里有块 LPC1114F 开发板,一直没时间玩,等不忙了好好向楼主学习下!!!
为方便大家设计,提供ADI样品。。。
点赞  2011-10-8 15:17

LPC11U14与LPC1343 USB寄存器比较

 

1.通过数据手册:

 

LPC11U14

1.jpg

 

LPC1343

 

2.jpg

 

 

2.通过芯片头文件:

 

LPC11U14

3.jpg  

LPC1343

4.jpg

 

从上面的两种比较可以看出,这两种芯片的寄存器已经发生了很大的变化,给我们移植带来了很大的麻烦,LPC1343继承了早期的LPC芯片(如LPC2148)寄存器,而LPC11U14的寄存器完全是新的概念了。

[ 本帖最后由 zhaojun_xf 于 2011-12-4 16:38 编辑 ]
我的博客
点赞  2011-12-4 16:30

由LPC11U14寄存器可以看出,并没用收发数据长度寄存器,而LPC1343则有,所以要实现接收数据实时返回就比较麻烦,因为我们不知道收发数据长度。还好NXP给出的例程中函数USB_ReadEP (),此函数可以返回实际接收数据的长度。

  1. /**************************************************************************************
    * FunctionName   : USB_ReadEP()
    * Description    : 读取USB端点数据
    * EntryParameter : EPNum - bit 0..3 地址;bit 7 方向;pData - 数据指针
    * ReturnValue    : 接收数据长度
    **************************************************************************************/
    uint32_t USB_ReadEP (uint32_t EPNum, uint8_t *pData)
    {
        return (cnt);
    }

 

通过此函数获取数据实际长度,我们很容易实现数据原样返回功能。不过这里样说明一点,在发生数据时要注意,如果PC发送的数据大于接收缓冲区时,它会分成几包发送的。

我的博客
点赞  2011-12-4 16:54
学习了,很有用的资料,感谢。
点赞  2011-12-22 11:54
不错不错 学习
点赞  2012-5-30 09:35
楼主 你的中文文档哪里搞的??
点赞  2012-5-30 09:41

回复 17楼 sudshine 的帖子

网上找的。。。。。。。。。。
我的博客
点赞  2012-5-30 10:09
好人啦。谢谢了。USB确实有难度资料就更少了。
点赞  2012-5-30 10:56
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复