这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的硬件设计非常简单,具体设计如下图所示:
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 编辑 ]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数据电平不翻转。
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; // 主机查询端点的时间间隔
}
报表描述符
报表描述符定义了执行设备功能的数据格式和使用方法。
报表描述符和USB的其他描述符是不一样的,它不是一个简单的表格,报表描述符是USB所有描述符中最复杂的。报表描述符非常复杂而有弹性,因为它需要处理各种用途的设备。报表的数据必须以简洁的格式来储存,这样才不会浪费设备内的储存空间以及数据传输时的总线时间。
实际上可以这样理解,报表内容的简洁,是通过报表描述符全面的、复杂的数据描述实现的。
报表描述符必须先描述数据的大小与内容。报表描述符的内容与大小因设备的不同而不同,在进行报表传输之前,主机必须先请求设备的报表描述符,只有得到了报表描述符才可正确解析报表的数据。
报表描述符是报表描述项目(Item)的集合,每一个描述项目都有相对统一的数据结构,项目很多,通过编码实现。
在HID的8种描述符中,最为重要而且复杂的应该是报表描述符,其定义了数据的存储格式和实际意义。如果能够正确的理解报表描述符,那么对数据的处理就能达到应用自如了,所以在设计描述符的时候,一定好多话费时间来理解和编写这一部分的内容。特别要主要以下几点:
1. 输入输出等项使用的数据必须是整数字节,如果没有完全使用到,也必须通过说明来补齐。
2.主要报表的三种项的应用及使用范围。
命令请求:
HID设备类特定的命令有6个:Get_Report、Get_Idle、Get_Protocol、Set_Report、Set_Idle、Set_Protocol。
[ 本帖最后由 zhaojun_xf 于 2011-9-20 07:51 编辑 ]通过近段时间来对NXP的HID例程的学习,对其有了个大致的了解,USB一个包含以下几个文件:
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 编辑 ]在HID开发中,报告描述符是最关键而且最复杂的描述符,因为它没有专门的格式,随意性比较大,但是HID的数据解析完全是依靠此描述符。
下面是NXP例程中的HID的报告描述符:
程序代码都注释了,这里不再详细说明,需要注意中间三段代码:
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 编辑 ]
通过上述对描述符的了解,基本的HID信息我们已经了解,下面就可以编写程序,通过把获取的数据进行验证了,这里我们是通过按键按下给PC发送数据,通过PC发送数据在设备上通过LED显示的。
[ 本帖最后由 zhaojun_xf 于 2011-9-27 07:45 编辑 ]
到此就可以把代码下载到开发板上,并通过实验进行验证了。下面我们采取两种方法:
1.使用周工例程中的HID Client上位机软件,进行验证。
把开发板下载代码后插入PC,通过Device选择我们的“LPC11Uxx USB HID”设备,下面我们可以看出,设备在没有键按下时读取为0x01,当按下键时,读取为0x00。在Outputs中勾选相应的复选框,我们可以看到开发板上相应的LED就别点亮了。
这种方法只是验证本实验是可以的,但是要开发其他USB功能设备就不行了,下面我们介绍一种通用的方法。
2. 使用Bus Hound软件验证,这个软件,刚开始很多人都不会用,这里将详细点。
打开软件,在设备项选择我们的USB设备,如下图
需要注意的是在发送数据时,需要选择USB人体学输入设备,而不是下面的HID-compliant device。如果是双击HID-compliant device弹出的窗口中并没有端点,是不能通信的,应该双击USB人体学输入设备,弹出如下界面:
通过上图,我们可以看出,端点和我们定义的是一样的
下面我们就可以选择端点进行数据通信了,选择需要端点,填写发送数据长度,在下面输入要发送的数据,选择“Run”,就可以把数据发送出去了。
之后把软件切换到Capture,可以捕获输入输出数据,如下图。
通过上面的验证,我们可以得知,实验结果和我们想要的是一样的,以后对于多字节的收发,我们就可以通过Bus Hound软件进行验证了。
[ 本帖最后由 zhaojun_xf 于 2011-9-27 08:05 编辑 ]通过上面的简单介绍,我们对HID有了一定的认识,下面我们可以根据需要把NXP的例程更改成我们实际需要的HID设备,进行进一步学习了。。。
本贴NXP HID具体例程代码如下(周工代码,里边有HIDClient软件):
自定义多字节发送的实现:
下面我们只需要修改几个部分就能实现了。
1. 修改报告描述符:
2. 修改端点描述符:
3. 修改输入输出变量:
4. 修改其他与InReport和OutReport相关的地方。
5. 编写代码实现接收后原样返回。
6. 试验一下:
[ 本帖最后由 zhaojun_xf 于 2011-9-27 22:06 编辑 ]
LPC11U14与LPC1343 USB寄存器比较
1.通过数据手册:
LPC11U14
LPC1343
2.通过芯片头文件:
LPC11U14
LPC1343
从上面的两种比较可以看出,这两种芯片的寄存器已经发生了很大的变化,给我们移植带来了很大的麻烦,LPC1343继承了早期的LPC芯片(如LPC2148)寄存器,而LPC11U14的寄存器完全是新的概念了。
[ 本帖最后由 zhaojun_xf 于 2011-12-4 16:38 编辑 ]由LPC11U14寄存器可以看出,并没用收发数据长度寄存器,而LPC1343则有,所以要实现接收数据实时返回就比较麻烦,因为我们不知道收发数据长度。还好NXP给出的例程中函数USB_ReadEP (),此函数可以返回实际接收数据的长度。
/**************************************************************************************
* 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发送的数据大于接收缓冲区时,它会分成几包发送的。