Skip to content

Commit

Permalink
Create additional altsetting with lower bandwidth
Browse files Browse the repository at this point in the history
Some newer XHCI firmware and Linux EHCI drivers are unhappy with
large bandwidth reservations on full-speed devices. To make them happy,
devices can request less bandwidth.

This does leave RGB out in the cold for such systems, but at least
16-bit formats will work fine with a lower bandwidth.

Refs #24
  • Loading branch information
kekiefer committed Oct 6, 2019
1 parent ef41048 commit 15f6474
Show file tree
Hide file tree
Showing 9 changed files with 88 additions and 45 deletions.
1 change: 1 addition & 0 deletions Inc/lepton.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#define TELEMETRY_OFFSET_LINES (IMAGE_NUM_LINES)

extern volatile uint8_t g_uvc_stream_status;
extern volatile uint16_t g_uvc_stream_packet_size;
extern volatile uint8_t g_lepton_type_3;
extern volatile uint8_t g_telemetry_num_lines;
extern volatile uint8_t g_format_y16;
Expand Down
21 changes: 12 additions & 9 deletions Middlewares/ST/STM32_USB_Device_Library/Class/video/Inc/usbd_uvc.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,20 @@

#define UVC_IN_EP 0x81 /* EP1 for data IN */
#define UVC_CMD_EP 0x82 /* EP2 for UVC commands */
#define VIDEO_PACKET_SIZE ((unsigned int)(962))
#define VIDEO_PACKET_SIZE_ALT1 ((unsigned int)(642)) /* 642 */
#define VIDEO_PACKET_SIZE_ALT2 ((unsigned int)(962))
#define VIDEO_PACKET_SIZE_MAX ((unsigned int)(1023))
#define VIDEO_MAX_SETUP_PACKET_SIZE ((unsigned int)(1024))
#define CMD_PACKET_SIZE ((unsigned int)(8))

#define CAM_FPS 9

/* min 162 for L2 Y16, 482 for L3 Y16 */
static const unsigned int VIDEO_PACKET_SIZE_ALT[] = {
VIDEO_PACKET_SIZE_ALT1,
VIDEO_PACKET_SIZE_ALT2
};

enum CUST_COMTROL_IDS {
CUST_CONTROL_COMMAND=0,
CUST_CONTROL_GET,
Expand Down Expand Up @@ -132,9 +140,10 @@ enum _vs_frame_indexes {
#define VS_FRAME_INDEX(NAME) VS_FRAME_INDEX_ ## NAME

#define USB_UVC_VCIF_NUM 0
#define USB_UVC_VSIF_NUM (char)1
#define USB_UVC_VSIF_ALT_START 1
#define USB_UVC_VSIF_ALT_COUNT 2

#define VIDEO_TOTAL_IF_NUM 2
#define VIDEO_TOTAL_IF_NUM (1 + USB_UVC_VSIF_ALT_COUNT)
#define WINDOWS_MAX_CONTROLS 31

typedef enum _vs_terminal_id {
Expand Down Expand Up @@ -262,12 +271,6 @@ struct uvc_input_terminal_desc {

#define SIZEOF_M(type, member) sizeof(((type *)0)->member)

#define UVC_DATA_HS_IN_PACKET_SIZE VIDEO_PACKET_SIZE
#define UVC_DATA_HS_OUT_PACKET_SIZE VIDEO_PACKET_SIZE

#define UVC_DATA_FS_IN_PACKET_SIZE VIDEO_PACKET_SIZE
#define UVC_DATA_FS_OUT_PACKET_SIZE VIDEO_PACKET_SIZE

#define UVC_LEN_IF_ASSOCIATION_DESC (char)8

#define UVC_VS_INTERFACE_INPUT_HEADER_DESC_SIZE(a,b) (char) (13+a*b)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ struct uvc_vs_frames_formats_descriptor {
struct UVC_FRAMES_FORMAT_UNCOMPRESSED(1) uvc_vs_frames_format_5;
};

struct uvc_vs_alt_setting {
struct usb_interface_descriptor intf;
struct usb_endpoint_descriptor ep;
};

struct usbd_uvc_cfg {
struct usb_config_descriptor usb_configuration;
struct usb_interface_assoc_descriptor usb_uvc_association;
Expand All @@ -54,8 +59,7 @@ struct usbd_uvc_cfg {
struct _UVC_INPUT_HEADER_DESCRIPTOR(1, VS_NUM_FORMATS) uvc_vs_input_header_desc;
struct uvc_vs_frames_formats_descriptor uvc_vs_frames_formats_desc;

struct usb_interface_descriptor uvc_vs_if_alt1_desc;
struct usb_endpoint_descriptor uvc_vs_if_alt1_ep;
struct uvc_vs_alt_setting uvc_vs_alt[USB_UVC_VSIF_ALT_COUNT];
} __attribute__ ((packed));

extern struct usbd_uvc_cfg USBD_UVC_CfgFSDesc_L2;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/* Standard VS Interface Descriptor = interface 1 */
// alternate setting 1 = operational setting
.uvc_vs_if_alt1_desc = {
.uvc_vs_alt[0].intf = {
.bLength = USB_DT_INTERFACE_SIZE, // 9
.bDescriptorType = USB_DESC_TYPE_INTERFACE, // 4
.bInterfaceNumber = USB_UVC_VSIF_NUM, // 1 index of this interface
.bInterfaceNumber = USB_UVC_VSIF_ALT_START + 0, // 1 index of this interface
.bAlternateSetting = 0x01, // 1 index of this setting
.bNumEndpoints = 0x01, // 1 one EP used
.bInterfaceClass = UVC_CC_VIDEO, // 14 Video
Expand All @@ -13,11 +13,33 @@
},

/* Standard VS Isochronous Video data Endpoint Descriptor */
.uvc_vs_if_alt1_ep = {
.uvc_vs_alt[0].ep = {
.bLength = USB_DT_ENDPOINT_SIZE, // 7
.bDescriptorType = USB_DESC_TYPE_ENDPOINT, // 5 (ENDPOINT)
.bEndpointAddress = UVC_IN_EP, // 0x83 EP 3 IN
.bmAttributes = USBD_EP_TYPE_ISOC, // 1 isochronous transfer type
.wMaxPacketSize = VIDEO_PACKET_SIZE,
.wMaxPacketSize = VIDEO_PACKET_SIZE_ALT1,
.bInterval = 0x01, // 1 one frame interval
},

.uvc_vs_alt[1].intf = {
.bLength = USB_DT_INTERFACE_SIZE, // 9
.bDescriptorType = USB_DESC_TYPE_INTERFACE, // 4
.bInterfaceNumber = USB_UVC_VSIF_ALT_START + 0, // 1 index of this interface
.bAlternateSetting = 0x02, // 2 index of this setting
.bNumEndpoints = 0x01, // 1 one EP used
.bInterfaceClass = UVC_CC_VIDEO, // 14 Video
.bInterfaceSubClass = UVC_SC_VIDEOSTREAMING, // 2 Video Streaming
.bInterfaceProtocol = UVC_PC_PROTOCOL_UNDEFINED, // 0 (protocol undefined)
.iInterface = 0x00, // 0 no description available
},

/* Standard VS Isochronous Video data Endpoint Descriptor */
.uvc_vs_alt[1].ep = {
.bLength = USB_DT_ENDPOINT_SIZE, // 7
.bDescriptorType = USB_DESC_TYPE_ENDPOINT, // 5 (ENDPOINT)
.bEndpointAddress = UVC_IN_EP, // 0x83 EP 3 IN
.bmAttributes = USBD_EP_TYPE_ISOC, // 1 isochronous transfer type
.wMaxPacketSize = VIDEO_PACKET_SIZE_ALT2,
.bInterval = 0x01, // 1 one frame interval
},
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
.uvc_vs_if_alt0_desc = {
.bLength = USB_DT_INTERFACE_SIZE, // 9
.bDescriptorType = USB_DESC_TYPE_INTERFACE, // 4
.bInterfaceNumber = USB_UVC_VSIF_NUM, // 1 index of this interface
.bInterfaceNumber = USB_UVC_VSIF_ALT_START, // 1 index of this interface
.bAlternateSetting = 0x00, // 0 index of this setting
.bNumEndpoints = 0x00, // 0 no EP used
.bInterfaceClass = UVC_CC_VIDEO, // 14 Video
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
.uvc_vs_if_alt0_desc = {
.bLength = USB_DT_INTERFACE_SIZE, // 9
.bDescriptorType = USB_DESC_TYPE_INTERFACE, // 4
.bInterfaceNumber = USB_UVC_VSIF_NUM, // 1 index of this interface
.bInterfaceNumber = USB_UVC_VSIF_ALT_START, // 1 index of this interface
.bAlternateSetting = 0x00, // 0 index of this setting
.bNumEndpoints = 0x00, // 0 no EP used
.bInterfaceClass = UVC_CC_VIDEO, // 14 Video
Expand Down
45 changes: 26 additions & 19 deletions Middlewares/ST/STM32_USB_Device_Library/Class/video/Src/usbd_uvc.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
// #define UVC_SETUP_REQ_DEBUG

volatile uint8_t g_uvc_stream_status = 0;
volatile uint16_t g_uvc_stream_packet_size = 0;
volatile uint8_t g_lepton_type_3 = 0;
volatile uint8_t g_telemetry_num_lines = 0;
volatile uint8_t g_format_y16 = 0;
Expand Down Expand Up @@ -228,7 +229,7 @@ static uint8_t USBD_UVC_Init (USBD_HandleTypeDef *pdev,
USBD_LL_OpenEP(pdev,
UVC_IN_EP,
USBD_EP_TYPE_ISOC,
VIDEO_PACKET_SIZE);
VIDEO_PACKET_SIZE_MAX);

USBD_LL_OpenEP(pdev,
UVC_CMD_EP,
Expand Down Expand Up @@ -323,22 +324,22 @@ static uint8_t USBD_UVC_Setup (USBD_HandleTypeDef *pdev,
{
USBD_LL_FlushEP (pdev,USB_ENDPOINT_OUT(0));

if (address == USB_UVC_VSIF_NUM)
if (address == USB_UVC_VCIF_NUM)
{
ret = ((USBD_UVC_ItfTypeDef *)pdev->pUserData)->VS_CtrlGet(req->bRequest,
(uint8_t *)hcdc->data,
req->wLength,
req->wIndex,
req->wValue);
ret = ((USBD_UVC_ItfTypeDef *)pdev->pUserData)->ControlGet(entity_id,
req->bRequest,
(uint8_t *)hcdc->data,
req->wLength,
req->wIndex,
req->wValue);
}
else
{
ret = ((USBD_UVC_ItfTypeDef *)pdev->pUserData)->ControlGet(entity_id,
req->bRequest,
(uint8_t *)hcdc->data,
req->wLength,
req->wIndex,
req->wValue);
ret = ((USBD_UVC_ItfTypeDef *)pdev->pUserData)->VS_CtrlGet(req->bRequest,
(uint8_t *)hcdc->data,
req->wLength,
req->wIndex,
req->wValue);
}

if (ret == USBD_OK)
Expand Down Expand Up @@ -407,12 +408,17 @@ static uint8_t USBD_UVC_Setup (USBD_HandleTypeDef *pdev,

// TODO: refactor this to callback user code instead of doing this here

if (ifalt == 1) {
DEBUG_PRINTF("USB_REQ_SET_INTERFACE: 1\r\n");
if (ifalt > 0) {
struct uvc_vs_alt_setting *alt;
// DEBUG_PRINTF("USB_REQ_SET_INTERFACE: 1\r\n");
g_uvc_stream_status = 1;
alt = &(g_lepton_type_3 ? USBD_UVC_CfgFSDesc_L3 : USBD_UVC_CfgFSDesc_L2).uvc_vs_alt[ifalt - USB_UVC_VSIF_ALT_START];
g_uvc_stream_packet_size = alt->ep.wMaxPacketSize;

} else {
DEBUG_PRINTF("USB_REQ_SET_INTERFACE: %d\r\n", req->wValue);
g_uvc_stream_status = 0;
g_uvc_stream_packet_size = 0;
}
}
else
Expand Down Expand Up @@ -521,24 +527,25 @@ static uint8_t USBD_UVC_EP0_RxReady (USBD_HandleTypeDef *pdev)
uint8_t address = (hcdc->CmdIndex >> 0) & 0xff;
uint8_t entity_id = (hcdc->CmdIndex >> 8) & 0xff;

if (address == USB_UVC_VSIF_NUM)
if (address == USB_UVC_VCIF_NUM)
{
ret = ((USBD_UVC_ItfTypeDef *)pdev->pUserData)->VS_CtrlSet(hcdc->CmdOpCode,
ret = ((USBD_UVC_ItfTypeDef *)pdev->pUserData)->ControlSet(entity_id,
hcdc->CmdOpCode,
(uint8_t *)hcdc->data,
hcdc->CmdLength,
hcdc->CmdIndex,
hcdc->CmdValue);
}
else
{
ret = ((USBD_UVC_ItfTypeDef *)pdev->pUserData)->ControlSet(entity_id,
hcdc->CmdOpCode,
ret = ((USBD_UVC_ItfTypeDef *)pdev->pUserData)->VS_CtrlSet(hcdc->CmdOpCode,
(uint8_t *)hcdc->data,
hcdc->CmdLength,
hcdc->CmdIndex,
hcdc->CmdValue);
}


hcdc->CmdOpCode = 0xFF;
}
return ret;
Expand Down
12 changes: 6 additions & 6 deletions Src/usb_task.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ PT_THREAD( usb_task(struct pt *pt))

static uint8_t uvc_header[2] = { 2, 0 };
static uint32_t uvc_xmit_row = 0, uvc_xmit_plane = 0, uvc_xmit_seg = 0;
static uint8_t packet[VIDEO_PACKET_SIZE];
static uint8_t packet[VIDEO_PACKET_SIZE_MAX];
static int image_num_segments;

PT_BEGIN(pt);
Expand Down Expand Up @@ -241,7 +241,7 @@ PT_THREAD( usb_task(struct pt *pt))
case VS_FMT_INDEX(GREY):
{
// while (uvc_xmit_row < 60 && count < VALDB(videoCommitControl.dwMaxPayloadTransferSize))
while (uvc_xmit_row < IMAGE_NUM_LINES && count < VIDEO_PACKET_SIZE)
while (uvc_xmit_row < IMAGE_NUM_LINES && count < g_uvc_stream_packet_size)
{
for (i = 0; i < FRAME_LINE_LENGTH; i++)
{
Expand All @@ -261,7 +261,7 @@ PT_THREAD( usb_task(struct pt *pt))
case VS_FMT_INDEX(Y16):
{
// while (uvc_xmit_row < 60 && count < VALDB(videoCommitControl.dwMaxPayloadTransferSize))
while (uvc_xmit_row < (IMAGE_NUM_LINES + g_telemetry_num_lines) && count < VIDEO_PACKET_SIZE)
while (uvc_xmit_row < (IMAGE_NUM_LINES + g_telemetry_num_lines) && count < g_uvc_stream_packet_size)
{
for (i = 0; i < FRAME_LINE_LENGTH; i++)
{
Expand All @@ -278,7 +278,7 @@ PT_THREAD( usb_task(struct pt *pt))
default:
case VS_FMT_INDEX(YUYV):
{
while (uvc_xmit_row < IMAGE_NUM_LINES && count < VIDEO_PACKET_SIZE)
while (uvc_xmit_row < IMAGE_NUM_LINES && count < g_uvc_stream_packet_size)
{
for (i = 0; i < FRAME_LINE_LENGTH; i++)
{
Expand All @@ -302,7 +302,7 @@ PT_THREAD( usb_task(struct pt *pt))
}
case VS_FMT_INDEX(BGR3):
{
while (uvc_xmit_row < IMAGE_NUM_LINES && count < VIDEO_PACKET_SIZE)
while (uvc_xmit_row < IMAGE_NUM_LINES && count < g_uvc_stream_packet_size)
{
for (i = 0; i < FRAME_LINE_LENGTH; i++)
{
Expand All @@ -318,7 +318,7 @@ PT_THREAD( usb_task(struct pt *pt))
}
case VS_FMT_INDEX(RGB565):
{
while (uvc_xmit_row < IMAGE_NUM_LINES && count < VIDEO_PACKET_SIZE)
while (uvc_xmit_row < IMAGE_NUM_LINES && count < g_uvc_stream_packet_size)
{
for (i = 0; i < FRAME_LINE_LENGTH; i++)
{
Expand Down
12 changes: 9 additions & 3 deletions Src/usbd_uvc_if.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ __ALIGN_BEGIN struct uvc_streaming_control videoCommitControl __ALIGN_END =
.wCompWindowSize = 0,
.wDelay = 0,
.dwMaxVideoFrameSize = MAX_FRAME_SIZE(80,60,VS_FMT_SIZE(YUYV)),
.dwMaxPayloadTransferSize = VIDEO_PACKET_SIZE,
.dwMaxPayloadTransferSize = VIDEO_PACKET_SIZE_ALT1,
.dwClockFrequency = 0,
.bmFramingInfo = 0,
.bPreferedVersion = 0,
Expand All @@ -140,7 +140,7 @@ __ALIGN_BEGIN struct uvc_streaming_control videoProbeControl __ALIGN_END =
.wCompWindowSize = 0,
.wDelay = 0,
.dwMaxVideoFrameSize = MAX_FRAME_SIZE(80,60,VS_FMT_SIZE(YUYV)),
.dwMaxPayloadTransferSize = VIDEO_PACKET_SIZE,
.dwMaxPayloadTransferSize = VIDEO_PACKET_SIZE_ALT1,
.dwClockFrequency = 0,
.bmFramingInfo = 0,
.bPreferedVersion = 0,
Expand Down Expand Up @@ -482,7 +482,6 @@ static int8_t UVC_VS_ControlGet (uint8_t cmd, uint8_t* pbuf, uint16_t length, u

rtnBuf->bFormatIndex = videoProbeControl.bFormatIndex;
rtnBuf->bFrameIndex = videoProbeControl.bFrameIndex;
rtnBuf->dwMaxPayloadTransferSize = VIDEO_PACKET_SIZE;
rtnBuf->dwFrameInterval = INTERVAL;

if (cmd == UVC_GET_DEF ||
Expand All @@ -492,6 +491,7 @@ static int8_t UVC_VS_ControlGet (uint8_t cmd, uint8_t* pbuf, uint16_t length, u
{
struct uvc_vs_frames_formats_descriptor *frames_formats;
struct UVC_FRAME_UNCOMPRESSED(1) *frame;
uint16_t payload_size;

if (g_lepton_type_3)
{
Expand All @@ -505,23 +505,29 @@ static int8_t UVC_VS_ControlGet (uint8_t cmd, uint8_t* pbuf, uint16_t length, u
switch (videoProbeControl.bFormatIndex) {
case VS_FMT_INDEX(YUYV):
frame = frames_formats->uvc_vs_frames_format_1.uvc_vs_frame;
payload_size = VIDEO_PACKET_SIZE_ALT[0];
break;
case VS_FMT_INDEX(Y16):
frame = frames_formats->uvc_vs_frames_format_2.uvc_vs_frame;
payload_size = VIDEO_PACKET_SIZE_ALT[0];
break;
case VS_FMT_INDEX(GREY):
frame = frames_formats->uvc_vs_frames_format_3.uvc_vs_frame;
payload_size = VIDEO_PACKET_SIZE_ALT[0];
break;
case VS_FMT_INDEX(RGB565):
frame = frames_formats->uvc_vs_frames_format_4.uvc_vs_frame;
payload_size = VIDEO_PACKET_SIZE_ALT[0];
break;
case VS_FMT_INDEX(BGR3):
frame = frames_formats->uvc_vs_frames_format_5.uvc_vs_frame;
payload_size = VIDEO_PACKET_SIZE_ALT[1];
break;
default:
return USBD_FAIL;
}
rtnBuf->dwMaxVideoFrameSize = frame[videoProbeControl.bFrameIndex - 1].dwMaxVideoFrameBufferSize;
rtnBuf->dwMaxPayloadTransferSize = payload_size;
}
else
{
Expand Down

0 comments on commit 15f6474

Please sign in to comment.