1. USB简介
USB:Universal Serial Bus(通用串行总线)。是一种常用于电子设备间通讯的通用标准接口。USB 总线作为一种高速串行总线,其极高的传输速度可以满足高速数据传输的应用环境要求。
具有供电简单(可总线供电)、安装配置便捷(支持即插即用和热插拔)、 扩展端口简易(通过集线器最多可扩展127 个外设)、传输方式多样化(4 种传输模式),以及兼容良好(产品升级后向下兼容)等优点。
1.1 EASY EAI Orin-Nano USB资源介绍
EASY EAI Orin-Nano有一路直出的USB3.0 HOST接口,还有一路直出的OTG接口。
若不了解【USB HOST】、【USB Device】以及【OTG】的含义,又或者有【必须使下层USB作为HOST】的需求,可参考《USB_HOST与USB_Device》一文。
1.2 USB摄像头接入方案
注意:虽然USB支持热插拔,但在没给底板加装外壳保护的情况下,很容易触碰到底板上的器件,甚至板卡附近有金属零件很容易造成板卡短路。因此也建议在插拔外设时,最好确保电源已经完全切断。
【建议】USB摄像头【直接】接入到底板的【上层】USB接口上。
虽然采用多路扩展方案,理论上可扩展127个设备,但在实际接入多个USB摄像头时需要考虑USB通道的带宽,USB集线层数,以及要解决设备ID相同的问题,因此非必要【不建议】这么接。
USB的理论最大层数为7层(含RootHub)。
1.3 USB设备的接入管理介绍
在USB摄像头或者USB Hub进行物理连接后,我们需要知道这些USB设备是否被系统识别出来,则需要通过lsusb命令查看。
lsusb
另外,在文件系统中,USB Device管理目录为/sys/bus/usb/devices,可在此处查看到从root_hub开始挂载的USB设备以及Hub设备的拓扑关系。
USB设备的设备命名方式规则如下:
设备对象的命名规则 | ||
设备 | 命名规则 | 描述 |
总线对象 | usb1、usb2 | 处理器自带的USB硬件,0号hub设备,所以其接口对象是由0开始计算。 |
直连的USB设备 | root_hub-hub_port 注:以“-”段横杠分割 | root_hub为所在的总线号码; hub_port为处于该总线的第几个设备,0号设备总线本身,新接入的设备从1开始。 |
连在外扩hub的设备 | root_hub-hub_port.device 注:以“.”句号分割 | 新接入的设备作为hub的子设备,编号从1开始 |
设备对象的接口命名规则 | ||
设备 | 命名规则 | 描述 |
设备对象的接口对象 | device_object:config.interface 注:以“:”冒号分割设备对象和后续元素。后续元素有配置和接口,二者以“.”句号分割 | device_object:设备对象,上面总线对象、质量设备、经过hub的设备统称为设备对象 |
config:USB设备的配置描述符,一个USB设备可在不同系统、不同架构下运行的前提就是使用了不同的配置描述符 | ||
interfece:USB设备的接口描述符,例如一个USB对讲机,有负责处理播音的接口以及负责录音的接口。 |
1.4 寻找可用的设备节点
rockchip平台,一个MIPI-CSI接口会对应20多个video节点(设备树定了就会生成这么多个),如下图所示。
而且MIPI-CSI camera对应的节点,会在修改内核设备树的时候固定下来(即:内核配好了MIPI-CSI Camera个数,无论MIPI-CSI摄像头是否有接上,它的video节点情况都是不会根据MIPI-CSI Camera的接入情况而【动态】改变)。
而一个USB camera会对应2个video节点,【一般会】排列在MIPI-CSI camera的后面。举个例子:内核配置了1路MIPI-CSI camera,那USB camera的节点就是/dev/video25和/dev/video26;内核配置了2路MIPI-CSI camera,那USB camera的节点就是/dev/video49和/dev/video50。以此类推。
但是【最准确】的方法,还是要看一下这个video节点的【描述信息】。Linux的v4l2框架会把这些节点的描述信息统一放在/sys/class/video4linux/目录下,如下图所示。
随便进入一个描述,如video22。
通过cat命令,可以用查看这个name的内容是什么。
cat /sys/class/video4linux/video22/name
那么,我们则需要使用以下命令,对【所有video节点】进行扫描与【筛选】。
grep -i "usb" /sys/class/video4linux/video*/name
2. 快速上手
2.1 例程源码下载
到【百度网盘】上下载相关的单例程序:
链接:https://pan.baidu.com/s/1RXHMGpmGSEfFy0rb1VkXSg?pwd=1234
提取码: 1234
比如在windows环境中,就把单例程序下载到:此电脑\D:\BaiduNetdisk (无规定,用户可自主选择),如下图所示。
然后把例程【复制粘贴】到nfs挂载目录中。(不清楚目录如何构建的,可以参考《入门指南/开发环境准备/nfs服务搭建与挂载》)
2.2 例程编译&运行
通过adb shell进入开发板环境,执行下方命令定位到demo目录,并且执行编译操作。
cd /home/orin-nano/Desktop/nfs/02_camera/
./build.sh
编译成功后,相关的demo会生成在Release目录下。
执行下方命令以运行demo,如下所示。
sudo ./Release/test-usbCam-single 49 ##需要root权限
执行效果如下所示。
然后把/tmp/photo拷贝到当前目录下的Release内
cp /tmp/photo ./Release/
再通过组合键【Ctrl+Shift+T】创建一个新窗口,定位到nfs服务器的对应位置。
最后使用mplayer工具播放图片,命令如下所示。
mplayer -demuxer rawvideo -rawvideo w=1280:h=720:format=bgr24 ./Release/photo -loop 0
例程默认分辨率为1280x720,故w和h的参数对应填入1280和720。当出现图片异常时,说明分辨率等不太对应于手头的摄像头,所以需要调整usbcamera_init()的分辨率,例如640x480。
3. 测试USB摄像头API案例
示例代码路径为:02_camera/test-usbCam/single-cam.c。USB Camera API的测试案例代码逻辑流程如下所示:
3.1 源码说明
int main()
{
if(1 == argc){
printf("\nerr: Missing parameter!\n");
printf("================= [usage] ==================\n");
printf("example:\n");
printf("\t%s <49/50>\n", argv[0]);
printf("--------------------------------------------\n");
return 0;
}
int cameraIndex = atoi(argv[1]);
char *pbuf = NULL;
int ret = 0;
int skip = 0;
FILE *fp = NULL;
ret = usbcamera_init(CAMERA_INDEX, CAMERA_WIDTH, CAMERA_HEIGHT, 0);
if (ret) {
printf("error: %s, %d\n", __func__, __LINE__);
goto exit3;
}
pbuf = (char *)malloc(IMAGE_SIZE);
if (!pbuf) {
printf("error: %s, %d\n", __func__, __LINE__);
ret = -1;
goto exit2;
}
//跳过前10帧
skip = 10;
while(skip--) {
ret = usbcamera_getframe(CAMERA_INDEX, pbuf);
if (ret) {
printf("error: %s, %d\n", __func__, __LINE__);
goto exit1;
}
}
/* tips: 可以在Ubuntu下用mplayer播放录制图像
* mplayer -demuxer rawvideo -rawvideo w=1280:h=720:format=bgr24 photo -loop 0
*/
fp = fopen("/tmp/photo", "w");
if (!fp) {
printf("error: %s, %d\n", __func__, __LINE__);
ret = -1;
goto exit2;
}
fwrite(pbuf, 1, IMAGE_SIZE, fp);
fclose(fp);
exit1:
free(pbuf);
pbuf = NULL;
exit2:
usbcamera_exit(CAMERA_INDEX);
exit3:
return ret;
}
其中usbcamera_init(),usbcamera_getframe(),usbcamera_exit()是对v4l2接口调用的易用化封装。具体实现于02_camera/commonApi/usb_camera/usb_camera.c。