打印

控制USB摄像头小结

[复制链接]
10730|13
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 kwell2009 于 2011-7-29 13:07 编辑

前段时间的控制摄像头读取图像的小结,还没全部完成,不过还是已经实现了的。
第一个USB项目,大家请拍砖。
其中USB HOST芯片为CH374,恒量下较SH811L便宜。

不过还是出了些问题,一开始是USB通讯时,接1.0的鼠标或者1.1HUB都正常,数据无误;换2.0的优盘或者摄像头则均出错,返回描述符时超过14字节的数据全部出现无规则的错位。为此挠了很久的头,都想着得换芯片了,后来问了沁恒的工程师,原来自己的芯片是很久以前有BUG的那一批,HOLY SHIT!我还是搜遍了赛格才找到的,真是坑爹啊。跟他们的MM拿了几个样片搞定了。



1.USB设备的枚举开始。枚举用的是控制传输,分三个阶段:建立阶段,数据阶段,状态阶段。每个阶段都包括主机与设备一来一回的信息传输:主机为发出令牌包等待回应或数据,设备为收到令牌包返回握手包或数据。

枚举过程参考圈圈的资料,不多叙述,只需对返回描述符的结构保存好。

我的设备是一个USB摄像头,返回的设备描述符为:

0x12 0x01 0x00 0x02 0xEF 0x02 0x01 0x40 0x45 0x0C 0xC0 0x620x00 0x01 0x02 0x01 0x00 0x01
其中我关注的字节是

0xEF -- bDeviceClass
又是挠头,2.0协议中提到这个 bDeviceClass 的也就是 HUB 类型(0x09),后来终于搜到了UVC(USB VIDEO CLASS)的资料(当时差点哭出声来)。在USB_Video_Class_1.1.pdf


it must set the bDeviceClass, bDeviceSubClass andbDeviceProtocol fields 0xEF, 0x02 and 0x01 respectively. This set of classcodes is defined as the Multi-interface Function Class codes.
好吧,这是一个多接口的设备。

然后设置设备地址,要求返回配置描述符,前4个字节:0x09 0x02 0x2A 0x02
纳闷了,0x022A = 554 这么庞大的配置描述符?用BUS HOUND抓了数据:




看来这玩意确实有这么多容量的配置描述符,但这里有两个ID,其中 Windows 接下来一直操作的是那个 (37) USB 视频设备 #3,而我 操作的是 (36) USBComposite Device ,效果也是一样。没写过Windows的驱动,不明白,知道的大虾给指点下。

相关帖子

沙发
kwell2009|  楼主 | 2011-7-25 09:07 | 只看该作者
本帖最后由 kwell2009 于 2011-7-29 10:58 编辑

2.配置设备。其实,照抄Windows的步骤就可以了,但我承认我蛋疼了,打印出整份配置描述符对着UVC的资料看,这里相关的包括USB_Video_Class_1.1.pdfUSB_Video_Payload_MJPEG_1.1.pdf

现在把关键的配置描述符分开标明:


0x09 0x02 0x2A 0x02 0x02 0x01 0x00 0x80 0x31


0x08 0x0B 0x00 0x02 0x0E 0x03 0x00 0x01


0x09 0x04 0x00 0x00 0x01 0x0E 0x01 0x00 0x01 -- VC interface descriptor


0x0D 0x24 0x01 0x00 0x01 0x67 0x00 0xC0 0xE1 0xE4 0x000x01 0x01


0x09 0x24 0x03 0x02 0x01 0x01 0x00 0x05 0x00 -- output trminal(ID 02)


0x1A 0x24 0x06 0x04 0x70 0x33 0xF0 0x28 0x11 0x63 0x2E0x4A 0xBA 0x2C 0x68 0x90 0xEB 0x33 0x40 0x16 0x08 0x01 0x03 0x01 0x2F 0x00 –extension unit (ID 04)


0x1A 0x24 0x06 0x05 0x3F 0xAE 0x12 0x28 0xD7 0xBC 0x110x4E 0xA3 0x57 0x6F 0x1E 0xDE 0xF7 0xD6 0x1D 0x08 0x01 0x04 0x01 0x00 0x00 –extension unit (ID 05)


0x12 0x24 0x02 0x01 0x01 0x02 0x00 0x00 0x00 0x00 0x000x00 0x00 0x00 0x03 0x00 0x00 0x00 – camera terminal (ID 01)


0x0B 0x24 0x05 0x03 0x01 0x00 0x00 0x02 0x3F 0x05 0x00 –processing unit(ID 03)


0x07 0x05 0x83 0x03 0x10 0x00 0x06


0x05 0x25 0x03 0x10 0x00


0x09 0x04 0x01 0x00 0x00 0x0E 0x02 0x00 0x00 – VS interface descriptor


0x0E 0x24 0x01 0x01 0x34 0x01 0x81 0x00 0x02 0x02 0x010x00 0x01 0x00 – input header(MJPEG)


0x0B 0x24 0x06 0x01 0x05 0x00 0x01 0x00 0x00 0x00 0x00


0x32 0x24 0x07 0x01 0x00 0x80 0x02 0xE0 0x01 0x00 0x2C0x01 0x00 0x00 0x28 0x23 0x00 0x00 0x2C 0x01 0x00 0x15 0x16 0x05 0x00 0x06 0x150x16 0x05 0x00 0x20 0xA1 0x07 0x00 0x2A 0x2C 0x0A 0x00 0x40 0x42 0x0F 0x00 0x800x84 0x1E 0x00 0x80 0x96 0x98 0x00 – frame01(640*480)


0x32 0x24 0x07 0x02 0x00 0x60 0x01 0x20 0x01 0x00 0x630x00 0x00 0x00 0x9A 0x0B 0x00 0x00 0x63 0x00 0x00 0x15 0x16 0x05 0x00 0x06 0x150x16 0x05 0x00 0x20 0xA1 0x07 0x00 0x2A 0x2C 0x0A 0x00 0x40 0x42 0x0F 0x00 0x800x84 0x1E 0x00 0x80 0x96 0x98 0x00


0x32 0x24 0x07 0x03 0x00 0x40 0x01 0xF0 0x00 0x00 0x4B0x00 0x00 0x00 0xCA 0x08 0x00 0x00 0x4B 0x00 0x00 0x15 0x16 0x05 0x00 0x06 0x150x16 0x05 0x00 0x20 0xA1 0x07 0x00 0x2A 0x2C 0x0A 0x00 0x40 0x42 0x0F 0x00 0x800x84 0x1E 0x00 0x80 0x96 0x98 0x00 – frame03(320*240)


0x32 0x24 0x07 0x04 0x00 0xB0 0x00 0x90 0x00 0xC0 0x180x00 0x00 0x80 0xE6 0x02 0x00 0xC0 0x18 0x00 0x00 0x15 0x16 0x05 0x00 0x06 0x150x16 0x05 0x00 0x20 0xA1 0x07 0x00 0x2A 0x2C 0x0A 0x00 0x40 0x42 0x0F 0x00 0x800x84 0x1E 0x00 0x80 0x96 0x98 0x00


0x32 0x24 0x07 0x05 0x00 0xA0 0x00 0x78 0x00 0xC0 0x120x00 0x00 0x80 0x32 0x02 0x00 0xC0 0x12 0x00 0x00 0x15 0x16 0x05 0x00 0x06 0x150x16 0x05 0x00 0x20 0xA1 0x07 0x00 0x2A 0x2C 0x0A 0x00 0x40 0x42 0x0F 0x00 0x800x84 0x1E 0x00 0x80 0x96 0x98 0x00


0x1B 0x24 0x03 0x00 0x05 0x80 0x02 0xE0 0x01 0x60 0x010x20 0x01 0x40 0x01 0xF0 0x00 0xB0 0x00 0x90 0x00 0xA0 0x00 0x78 0x00 0x01 0x00


0x06 0x24 0x0D 0x01 0x01 0x04


0x09 0x04 0x01 0x01 0x01 0x0E 0x02 0x00 0x00 – alternate setting 01


0x07 0x05 0x81 0x05 0x80 0x00 0x01 – endpoint(128 bytes)


0x09 0x04 0x01 0x02 0x01 0x0E 0x02 0x00 0x00 – alternate setting 02


0x07 0x05 0x81 0x05 0x00 0x01 0x01 – endpoint(256 bytes)


0x09 0x04 0x01 0x03 0x01 0x0E 0x02 0x00 0x00


0x07 0x05 0x81 0x05 0x00 0x02 0x01


0x09 0x04 0x01 0x04 0x01 0x0E 0x02 0x00 0x00


0x07 0x05 0x81 0x05 0x58 0x02 0x01


0x09 0x04 0x01 0x05 0x01 0x0E 0x02 0x00 0x00


0x07 0x05 0x81 0x05 0x20 0x03 0x01


0x09 0x04 0x01 0x06 0x01 0x0E 0x02 0x00 0x00


0x07 0x05 0x81 0x05 0xBC 0x03 0x01





其中,input header descriptorbDescriptorSubtype=06说明其图像格式为MJPEG(USB_Video_Payload_MJPEG_1.1.pdf75,136),故接下来的内容得对着USB_Video_Payload_MJPEG_1.1.pdf 看。



区分开配置描述符中的各项后,Windows开始对设备进行配置,首先设置 VS接口(set interface),命令为:

01 0b 00 00 01 00 00 00
为设置VS接口的备用0接口(alternating interface),先获取各个参数,先是:

a1 XX 00 YY 00 04 ZZ 00
04 -- 为第一个extension unit ID

和:

a1 XX 00 YY 00 03 ZZ 00
03 -- processing unit ID
获取processing unit 的信息可以理解,因为其包括大量摄像头的参数(USB_Video_Class_1.1.pdf138)但是获取大量的 extension unit 的信息我就挠头了,资料里也找不着,只有一个XU_CONTROL_UNDEFINED—00,还一点都不沾边,不懂不懂。

到此为止,Windows一直在获取设备的信息,判断其当前值是否在允许范围之内,该USB摄像头的设置没有超出允许值,故没有 SET CUR 的命令。所以,我华丽的将这一大段无视了。

接下来,设置点亮摄像头的背光

,并检查是否设置成功:


(为什么是01这个值,为什么?找不到找不到)。然后根据VS_PROBE_CONTROL, VS_COMMIT_CONTROL(USB_Video_Class_1.1.pdf116) 的值,设置VS_STILL_PROBE_CONTROL, VS_STILL_COMMIT_CONTROL(USB_Video_Class_1.1.pdf129)。其中,这4个接口控制(interfacecontrol,不知该怎么翻译)中,bFormatIndex bFrameIndex 是需要设置的:

前者根据input header bNumFormats来设置,这里为1,只有一个,故为 01

后者根据你要得到的图片分辨率来设置,我需要320*240,故为03

还要设置激活(set interface 不知该怎么表达,类似于使能吧)你需要的接口配置(alternatingsetting)

01 0b 01 00 01 00 00 00
需要注意的是:作为主机的CH374接收缓冲区最大只有128字节,所以,根据接口对应的端点大小,选择接口配置01(128字节)

09 04 01 01 01 0e 02 00 00
07 05 81 05 80 00 01
端点描述符标明,该端点传输模式为等时传输(isochronous transfer)

以下是windows的设置过程,照着改就行了。

使用特权

评论回复
板凳
kwell2009|  楼主 | 2011-7-25 09:08 | 只看该作者
本帖最后由 kwell2009 于 2011-7-29 11:08 编辑

3.开始等时传输

类似于控制传输的一个阶段,主机控制CH374对我们需要的端点 0x81 发出IN令牌包,此时,摄像头收到令牌包后立刻开始捕捉图像、编码并传送数据,等待CH374中断信号,读取其接受缓冲区的128字节数据。

参照 usb2.0协议第73页,数据包为128字节的情况,1ms最多可发送10个数据包。但最慢需要在1ms内将128字节的数据包取走并开始新的一次等时传输,否则会丢包,而等时传输没有重发机制,丢了就等于没有了。

参照 USB_Video_Payload_MJPEG_1.1.pdf9页以及 USB_Video_Class_1.1.pdf44页,分析数据头(12字节)

0c 8c 7a 54 93 18 e41b 9e 18 8e 03
其中第二字节在 8c 8d 之间转换,表示不同的两帧摄像头图像,此帧图像分别以 8e 8f 结束,以此来判断一帧图像的完整接收。

最后两个字节为收到此数据包时SOF的编号,亦即时间戳(SOF频率为1KHz),同1ms内收到的数据包编号相同。

然后就是数据,将此N帧数据整合于一起就是一帧图像了。如果已经得到想要的数据,想停止等时传输,BUS HOUND 只显示:


没做过Windows底下的驱动,不晓得神马是 RSET,找了前辈写的WINCE底下UVC的驱动,半天没看到RESET字样的东东。又问了老大,说是没做过USBD层面的驱动,也不清楚,让我去看USBD。编译了个最小的WINCE,查抄关键字(省略一千字)...查到最后,居然只有这句话:

LPRESET_PIPE lpResetPipe;typedef BOOL (* LPRESET_PIPE)(
USB_PIPE hPipe
);
内牛满面啊......想怕只是系统里一些结构的初始化而已吧,继续无视,直接对摄像头发命令:

01 0b 00 00 01 00 00 00
搞定。只需设置(即使能)摄像头的VS接口的备用0控制接口,即可停止当前的等时传输,要再次开始传输,只需再次配置好 Processing Unit,并设置接口配置即可。路过的大虾知道这个RSET的给说说道理吧。


这里又有一些问题,我在等时传输读取摄像头数据中,会不定时的出现CH374等待超时的情况(概率大概为50%),此时CH374的寄存器
REG_USB_STATUS
值为 0x80,即设备应答错误或者超时无应答。此时无论对摄像头进行其他任何操作都没有反应,均为等待超时。该摄像头是接在HUB上的,我读了此时HUB上对应摄像头的PORT的状态为:

0x01 0x01 0x02 0x00
复位此端口后,第2字节仍为0x02参照 usb2.0协议第454455页可以知道是 PORT_ENABLE 出现了异常,当然,对此端口进行复位并重新设置摄像头是可以继续捕获图像,不过太耗时了,而且它两三下给我来一次异常的话就麻烦了,大侠们给讲解一下吧,这个我真没搞定。



至此,用MCU控制USB摄像头读取图像的步骤已完成。请大家来拍砖。

使用特权

评论回复
地板
dragonathust| | 2011-7-26 16:32 | 只看该作者
有价值

使用特权

评论回复
5
reconfig_alic| | 2011-7-27 08:53 | 只看该作者
好文顶起来

使用特权

评论回复
6
cheng105| | 2011-7-27 11:22 | 只看该作者
不错,顶下

使用特权

评论回复
7
kwell2009|  楼主 | 2011-7-29 10:11 | 只看该作者
针对文中可疑的地方,各位有什么意见都请提出来,我尽快做做实验看看结果。

使用特权

评论回复
8
kwell2009|  楼主 | 2011-8-3 11:20 | 只看该作者
看来大家不是特别感兴趣。由于该应用中,CH374的不定因素尚未确定,可能得考虑换主控芯片,打算直接上STM32F105/107,以后可能另开新帖再谈谈心得吧。

使用特权

评论回复
9
jy1975jy1975| | 2011-8-6 16:51 | 只看该作者
不错继续努力

使用特权

评论回复
10
tomas小火车| | 2012-9-8 15:48 | 只看该作者
想问下楼主,选择128字节接口的配置怎么发

使用特权

评论回复
11
13066| | 2013-6-2 09:51 | 只看该作者
请问楼主,能看看你的硬件连接吗?

使用特权

评论回复
12
ljing1963| | 2013-6-3 15:28 | 只看该作者

使用特权

评论回复
13
freeman9507| | 2014-6-27 22:19 | 只看该作者
顶顶顶顶的

使用特权

评论回复
14
louisignal| | 2015-11-28 14:51 | 只看该作者
目前正在做STM32F105 USB HUB扩展,MARK一下。楼主能留个QQ或者邮箱就好了。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:堆码,调试,抓狂...

1

主题

51

帖子

2

粉丝