Skip navigation
Home > All Places > USB > USB Superspeed Peripherals > Blog > 2019 > June
2019

在本篇blog中,我们学习如何在UVC 应用中实现对图像属性的控制。本篇笔记中应用到的 固件 为 第四篇笔记 的附件,硬件 为 CX3 Denebola 板。

 

从 UVC 1.5 协议上可以看到,亮度控制属于 processing unit的内容,必需支持的控制命令有 SET_CUR、GET_CUR、GET_MIN、GET_MAX、GET_RES、GET_INFO 和 GET_DEF。

BaiduShurufa_2019-6-13_10-11-21.png

 

首先,在cycx3_uvcdscr.c 描述符文件中找到 processing unit 描述符部分

    /* Processing Unit Descriptor */
    0x0D,                               /* Descriptor size */
    CX3_CS_INTRFC_DESCR,                /* Class specific interface desc type */
    0x05,                               /* Processing Unit Descriptor type: VC_PROCESSING_UNIT*/
    0x02,                               /* ID of this unit */
    0x01,                               /* Source ID: 1: Conencted to input terminal */
    0x00, 0x40,                         /* Digital multiplier */
    0x03,                               /* Size of controls field for this terminal: 3 bytes */
    0x00, 0x00, 0x00,                   /* No controls supported */
    0x00,                               /* String desc index: Not used */
    0x00,                               /* Analog Video Standards Supported: None */

 

查询 UVC 协议可以看到,Byte 8/9/10 用来指定UVC支持哪些控制属性。

BaiduShurufa_2019-6-13_10-21-50.png

可以看到,bit[0] 用来指定是否支持亮度控制,所以这里我们将 bit[0] 设置为1.

    /* Processing Unit Descriptor */
    0x0D,                               /* Descriptor size */
    CX3_CS_INTRFC_DESCR,                /* Class specific interface desc type */
    0x05,                               /* Processing Unit Descriptor type: VC_PROCESSING_UNIT*/
    0x02,                               /* ID of this unit */
    0x01,                               /* Source ID: 1: Conencted to input terminal */
    0x00, 0x40,                         /* Digital multiplier */
    0x03,                               /* Size of controls field for this terminal: 3 bytes */
    0x01, 0x00, 0x00,                   /* Brigntness control is supported */
    0x00,                               /* String desc index: Not used */
    0x00,                               /* Analog Video Standards Supported: None */

 

在函数 CyCx3UvcAppUSBSetupCB 中添加如下代码

 

#ifdef Add_brightness_control
/* Handle Video control commands here*/
        status =  HandleVCInterfaceRequest(wIndex, wValue, bRequest);
            if (status != CY_U3P_SUCCESS)
            {
                CyU3PDebugPrint (4, "\n\rUSBStpCB:VCI SendEP0Data = %d", status);
                isHandled=CyFalse;
            }
            else
            isHandled = CyTrue;


#endif

 

添加 定义

 

#ifdef Add_brightness_control


CyU3PReturnStatus_t HandleVCInterfaceRequest(uint16_t wIndex, uint16_t wValue,uint8_t bRequest)
{
CyU3PReturnStatus_t status = CY_U3P_ERROR_BAD_ARGUMENT;
  if (CY_U3P_GET_MSB(wIndex) == CX3_UVC_VC_PROCESSING_UNIT_ID) /*Video Control- Camera Teminal*/
  {
    CyU3PDebugPrint(4,"\n\r\n\rLine:%d\tVC:T ID 0x%x CS 0x%x Req 0x%x ", __LINE__,CY_U3P_GET_MSB(wIndex), wValue, bRequest);


    switch (wValue)
    {
    case CX3_UVC_PU_BRIGHTNESS_CONTROL: /*LED control*/
        CyU3PDebugPrint(4,"\r\n Brightness control\n");
      status = HandleBrightnessControlReq(bRequest);
      break;


    default:
//       glerrorstatus = VC_ERROR_CODE_INVALID_CONTROL;
      break;
    }
  }
return status;
}




CyU3PReturnStatus_t HandleBrightnessControlReq(uint8_t bRequest)
{
CyU3PReturnStatus_t status=1;
uint16_t readCount;
uint8_t WrBuff[2]={0,0},RdBuff;
switch(bRequest)
{
case CX3_USB_UVC_GET_CUR_REQ:
WrBuff[0] = Brightness.CurrentVal;
        CyU3PDebugPrint(4,"\r\nLine:%d  UVC Brightness get cur %d\n",__LINE__,WrBuff);
break;


case CX3_USB_UVC_SET_CUR_REQ:
        status = CyU3PUsbGetEP0Data (2, &WrBuff[0], &readCount);
CyU3PDebugPrint(4,"\r\n Line:%d UVC brightness set cur %d\n",__LINE__,WrBuff);
return status;
break;


case CX3_USB_UVC_GET_MIN_REQ:
WrBuff[0] = Brightness.MinVal;
        CyU3PDebugPrint(4,"\r\n Line:%d UVC brightness get Min %d\n",__LINE__,WrBuff);
break;
case CX3_USB_UVC_GET_MAX_REQ:
WrBuff[0] = Brightness.MinVal;
        CyU3PDebugPrint(4,"\r\n Line:%d UVC brightness get Max %d\n",__LINE__,WrBuff);
break;
case CX3_USB_UVC_GET_RES_REQ:
WrBuff[0] = Brightness.Res;
        CyU3PDebugPrint(4,"\r\n Line:%d UVC brightness get RES %d\n",__LINE__,WrBuff);
break;
case CX3_USB_UVC_GET_INFO_REQ:
WrBuff[0] = Brightness.Info;
        CyU3PDebugPrint(4,"\r\n Line:%d UVC brightness get INFO %d\n",__LINE__,WrBuff);
        break;
case CX3_USB_UVC_GET_DEF_REQ:
WrBuff[0] = Brightness.DefaultVal;
        CyU3PDebugPrint(4,"\r\n Line:%d UVC brightness get default %d\n",__LINE__,WrBuff);
break;
case CX3_USB_UVC_GET_LEN_REQ:
WrBuff[0] = 2;
        CyU3PDebugPrint(4,"\r\n Line:%d UVC brightness get len %d\n",__LINE__,WrBuff);
break;
default:
CyU3PUsbStall(0,CyTrue,CyFalse);
break;


}
status = CyU3PUsbSendEP0Data(2,(uint8_t*)&WrBuff);
if (status != 0)
{
CyU3PDebugPrint(4,"\n\r Send EP0 Data failed = 0x%X", status);
}


return status;


}


#endif























 

 

关于其他必要的变量定义和函数声明,请参考附件工程。编译工程并下载到Demo板中,在E-cam viewer属性面板中我们可以看到 亮度控制已经使能。

BaiduShurufa_2019-6-13_14-1-10.png

 

更多细节信息,请参考附件工程。

添加其他控制属性的步骤和亮度控制的步骤方法一致,这里就不再重复。

在前面三篇中,我们学习了如何选定适用于 CX3 的Image sensor/ISP 、如何构建 UVC 工程模板,以及一些调试 CX3 UVC 应用的基本方法。

在本篇笔记中,我们将会对前述的调试的笔记进行回顾和补充。为方便说明和理解,我们会按照第二篇学习笔记,采用 CX3 配置向导生成工程模板,在 Denebola 板上进行演示。如未另外说明,本笔记涉及到的 函数名、变量名、文件名等对应于附件工程。

 

  • 关于配置工具中参数的说明

首先我们熟悉下 CX3 配置工具的界面、参数的含义以及如何进行正确配置。

BaiduShurufa_2019-6-12_16-2-47.png

 

 

 

 

BaiduShurufa_2019-6-12_16-7-31.png

 

用户可以参考如上两幅截图,了解配置工具界面以及涉及到的参数说明。其中,sensor 部分的参数需要和 sensor 的技术人员确认准确。配置工具会根据用户输入的参数,判断输入的 CX3 端的 PLL 参数是否与之匹配。如果不匹配,则会出现警告,用户需要根据警告信息修正对应的参数,直到工具没有报错为止。

用户可以看到,很多参数都是 具有 范围的,即 最小值 和最大值,并不是唯一值。也就是说,对于某个分辨率的配置,可行的参数并不是唯一的一组,一般会有不同的几组。

 

  • 关于固件调试的方法

前面我们提到过,在调试 CX3 固件时,需要首先确保 CX3 摄像头在连接到主机端后,能够正确枚举为一个 UVC 设备。默认的情况下,在系统上电后,会执行CyCx3UvcAppInit()函数。此函数会初始化 必要的硬件模块、注册设备描述信息、配置端点、DMA 以及初始化 MIPI CSI 接口。需要保证CyCx3UvcAppInit 成功执行并返回。

用户可以用 BUS HOUND、USBlyzer,UART terminal等软件工具或者 硬件的 USB 协议分析仪抓取 USB通信判断函数执行过程和结果。此时,在设备管理器里,用户应当能看到名为 CX3-UVC 的设备。如果没有显示或者有黄色感叹号,一般是因为主机不能正确获取描述符或者回复的描述符不正确,需要着重进行检查。

BaiduShurufa_2019-6-12_14-49-23.png

 

当用户在主机端用 看图软件(MPC-HC、E-cam viewer 或者Amcap 等软件)打开相机并选择分辨率后,固件会运行到 CyCx3UvcAppHandleSetCurReq() 函数 执行CyCx3UvcAppImageSensorSetVideoResolution() 函数。这个函数的输入参数是 frame index, 这个数值其实是对应到描述符文件 cycx3_uvcdscr.c 里定义的 frame 的index。

BaiduShurufa_2019-6-12_15-7-3.png

此处的固件只配置了一个 分辨率,所以index 为1。如果用户手动添加新的分辨率,请注意index 的值需要是正确的。

 

回到CyCx3UvcAppImageSensorSetVideoResolution() 函数,这个函数根据选择的 分辨率 的序号对 MIPI CSI 接口和 sensor 进行配置,此处需要确保 这两处的配置正确。

对于 MIPI CSI 接口,用户可以调用 CyU3PMipicsiQueryIntfParams() 函数读回配置参数,检查是否和固件里配置的一致。

对于 sensor 或者 ISP,可以调用 I2C 读函数 读回写出的所有寄存器,与写出的参数进行比较,确保所有的寄存器都已正确配置。

 

配置完成后,sensor 或者 ISP 则会输出信号,使用示波器对信号进行检查(详见第三篇笔记),确保CX3 端信号解析正确。

 

另外,可以使用 UART 接口提供 debug 信息。附件工程定义了 宏 PRINT_FRAME_INFO, 用户可以查看

 

#ifdef PRINT_FRAME_INFO
...
...
#endif

 

部分的代码已获知细节。特别的,附件固件在 主线程中循环打印 frame相关信息。

/*For video streaming application of higher FPS refrain from using this debug print or try to reduce the print information*/
CyU3PDebugPrint(4,"\n\rProd = %d Cons = %d  Prtl_Sz = %d Frm_Cnt = %d Frm_Sz = %d B", TxCountflag, RxCountflag, PartialBufSize, FrameCount, ((TxCountflag*CX3_UVC_DATA_BUF_SIZE)+PartialBufSize));
Printflag = 0;


if (fpsflag == 1)
{
fps = 30000/(time1 -time0); //FPS calculate using time difference for 30 frames
CyU3PDebugPrint(4,"\n\rTimeDiff = %d ms FPS = %d", (time1 -time0), fps);
fpsflag = 0;




}

 

 

此处需要检查打印的 Prod 是否等于 Cons 的数量,Partial 包的大小为每一帧最后一个包的大小,这个值需要稳定不变(在分辨率没有切换时),FrameCount需要连续,没有丢帧。((TxCountflag*CX3_UVC_DATA_BUF_SIZE)+PartialBufSize)是计算的每一帧的大小,这个值需要与设定的分辨率大小一致。

 

注意,不要在 DMACallBack 函数里调用任何的UART 打印函数。

 

  • 其他相关的KBA 或者 论坛帖子

CX3 视频时间参数解析 – KBA226779 (ZH)

How to configure the MIPI Receiver in CX3 ?

How to configure CX3 MIPI receiver configuration for streaming RAW10 4096x3072 @ 10 fps ?

Streaming RAW10 Format Input Data to 16/24-bit Output Format in CX3 MIPI CSI-2 - KBA224387

Invalid Sequence Error in Multi-Channel Commit Buffer - KBA218830

CX3, i2c , 2-bytes address, 2-bytes data