Skip to content

Commit 5eb38f5

Browse files
author
Josuah Demangeon
committed
samples: usb: uvc_uvb: connecting USB device to host via UVB
Add a sample to experiment the USB Video Class host support by using the existing Zephyr USB Video Class device support. This allows running implementing the host side from the device side. Signed-off-by: Josuah Demangeon <[email protected]>
1 parent 05ffa1c commit 5eb38f5

File tree

9 files changed

+299
-0
lines changed

9 files changed

+299
-0
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
cmake_minimum_required(VERSION 3.20.0)
4+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
5+
project(uvc_uvb)
6+
7+
# This sample cannot use the common USB sample infrastructure as we do not want
8+
# to initialize the board default `zephyr_udc0` but instead an unrelated `virtual_udc0`.
9+
#include(${ZEPHYR_BASE}/samples/subsys/usb/common/common.cmake)
10+
11+
FILE(GLOB app_sources src/*.c)
12+
target_sources(app PRIVATE ${app_sources})
13+
zephyr_include_directories(${ZEPHYR_BASE}/subsys/usb/host)

samples/subsys/usb/uvc_uvb/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Copyright The Zephyr Project Contributors
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
# Source common USB sample options used to initialize new experimental USB
5+
# device stack. The scope of these options is limited to USB samples in project
6+
# tree, you cannot use them in your own application.
7+
source "samples/subsys/usb/common/Kconfig.sample_usbd"
8+
9+
source "Kconfig.zephyr"
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Zephyr UVC Host Testbench
2+
3+
This repo is there to experiment with UVC Host support in Zephyr.
4+
5+
Uses the USB Virtual Bus to connect the virtual USB host to the virtual USB device together.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/ {
8+
virtual_uhc0: uhc-virtual {
9+
compatible = "zephyr,uhc-virtual";
10+
maximum-speed = "full-speed";
11+
12+
virtual_udc0: udc-virtual {
13+
compatible = "zephyr,udc-virtual";
14+
num-bidir-endpoints = <4>;
15+
maximum-speed = "full-speed";
16+
17+
uvc_device: uvc-device {
18+
compatible = "zephyr,uvc-device";
19+
};
20+
};
21+
};
22+
};
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CONFIG_LOG=y
2+
CONFIG_UDC_DRIVER_LOG_LEVEL_INF=y
3+
CONFIG_UHC_DRIVER_LOG_LEVEL_INF=y
4+
CONFIG_USBD_VIDEO_CLASS=y
5+
CONFIG_USBD_VIDEO_LOG_LEVEL_INF=y
6+
CONFIG_USBH_LOG_LEVEL_INF=y
7+
CONFIG_USB_DEVICE_STACK_NEXT=y
8+
CONFIG_USB_HOST_STACK=y
9+
CONFIG_UVB_LOG_LEVEL_INF=y
10+
CONFIG_VIDEO=y
11+
CONFIG_VIDEO_LOG_LEVEL_INF=y
12+
CONFIG_UDC_BUF_POOL_SIZE=2048
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef NORDIC_USBH_TESTS_APP_H
8+
#define NORDIC_USBH_TESTS_APP_H
9+
10+
#include <stdint.h>
11+
#include <zephyr/usb/usbd.h>
12+
#include <zephyr/usb/usbh.h>
13+
14+
struct usbd_context *app_usbd_init_device(void);
15+
struct usbh_contex *app_usbh_init_controller(void);
16+
17+
#endif /* NORDIC_USBH_TESTS_APP_H */
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/device.h>
8+
#include <zephyr/logging/log.h>
9+
#include <zephyr/usb/usbd.h>
10+
#include <zephyr/usb/usbh.h>
11+
#include <zephyr/usb/class/usbd_uvc.h>
12+
13+
#include "usbh_device.h"
14+
#include "usbh_ch9.h"
15+
#include "usbh_class.h"
16+
17+
LOG_MODULE_REGISTER(app_main, LOG_LEVEL_INF);
18+
19+
#include "app.h"
20+
21+
#define APP_USBH_CLASS_DESC_MAX_SIZE 512
22+
23+
int usbh_class_init(struct usb_device *udev)
24+
{
25+
const size_t len = APP_USBH_CLASS_DESC_MAX_SIZE;
26+
struct net_buf *buf;
27+
int ret;
28+
29+
buf = usbh_xfer_buf_alloc(udev, len);
30+
if (buf == NULL) {
31+
LOG_ERR("Failed to allocate a host transfer buffer");
32+
return -ENOMEM;
33+
}
34+
35+
ret = usbh_req_desc(udev, USB_DESC_DEVICE, 0, 0, len, buf);
36+
if (ret != 0) {
37+
LOG_ERR("Failed to request descriptor");
38+
return ret;
39+
}
40+
41+
LOG_HEXDUMP_INF(buf->data, buf->len, "buf");
42+
43+
return 0;
44+
}
45+
46+
const struct device *const uvc_dev = DEVICE_DT_GET(DT_NODELABEL(uvc_device));
47+
const struct device *const video_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_camera));
48+
49+
int main(void)
50+
{
51+
struct usbd_context *app_usbd;
52+
struct usbh_contex *app_usbh;
53+
int ret;
54+
55+
uvc_set_video_dev(uvc_dev, video_dev);
56+
57+
/* Enable the virtual USB device and virtual USB host so they can
58+
* communicate together via UVB.
59+
*/
60+
61+
app_usbd = app_usbd_init_device();
62+
if (app_usbd == NULL) {
63+
LOG_ERR("Failed to initialize USB Device contexts");
64+
return 0;
65+
}
66+
67+
app_usbh = app_usbh_init_controller();
68+
if (app_usbh == NULL) {
69+
LOG_ERR("Failed to initialize USB Host controller");
70+
return 0;
71+
}
72+
73+
ret = usbh_enable(app_usbh);
74+
if (ret != 0) {
75+
LOG_ERR("Failed to enable USB Host");
76+
return 0;
77+
}
78+
79+
ret = usbd_enable(app_usbd);
80+
if (ret != 0) {
81+
LOG_ERR("Failed to enable USB Device");
82+
return 0;
83+
}
84+
85+
return 0;
86+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
* Copyright (c) 2023-2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <stdint.h>
8+
9+
#include <zephyr/device.h>
10+
#include <zephyr/usb/usbd.h>
11+
12+
#include <zephyr/logging/log.h>
13+
LOG_MODULE_REGISTER(usbd_app_config);
14+
15+
#define ZEPHYR_PROJECT_USB_VID 0x2fe3
16+
#define APP_USBD_PID 0x9999
17+
18+
/* doc device instantiation start */
19+
USBD_DEVICE_DEFINE(app_usbd,
20+
DEVICE_DT_GET(DT_NODELABEL(virtual_udc0)),
21+
ZEPHYR_PROJECT_USB_VID, APP_USBD_PID);
22+
/* doc device instantiation end */
23+
24+
/* doc string instantiation start */
25+
USBD_DESC_LANG_DEFINE(app_lang);
26+
USBD_DESC_MANUFACTURER_DEFINE(app_mfr, "Nordic");
27+
USBD_DESC_PRODUCT_DEFINE(app_product, "Virtual USB device");
28+
29+
/* doc string instantiation end */
30+
31+
USBD_DESC_CONFIG_DEFINE(fs_cfg_desc, "FS Configuration");
32+
33+
/* doc configuration instantiation start */
34+
static const uint8_t attributes = 0;
35+
USBD_CONFIGURATION_DEFINE(app_fs_config, attributes, 200, &fs_cfg_desc);
36+
/* doc configuration instantiation end */
37+
38+
struct usbd_context *app_usbd_init_device(void)
39+
{
40+
int err;
41+
42+
/* doc add string descriptor start */
43+
err = usbd_add_descriptor(&app_usbd, &app_lang);
44+
if (err) {
45+
LOG_ERR("Failed to initialize language descriptor (%d)", err);
46+
return NULL;
47+
}
48+
49+
err = usbd_add_descriptor(&app_usbd, &app_mfr);
50+
if (err) {
51+
LOG_ERR("Failed to initialize manufacturer descriptor (%d)", err);
52+
return NULL;
53+
}
54+
55+
err = usbd_add_descriptor(&app_usbd, &app_product);
56+
if (err) {
57+
LOG_ERR("Failed to initialize product descriptor (%d)", err);
58+
return NULL;
59+
}
60+
/* doc add string descriptor end */
61+
62+
/* doc configuration register start */
63+
err = usbd_add_configuration(&app_usbd, USBD_SPEED_FS,
64+
&app_fs_config);
65+
if (err) {
66+
LOG_ERR("Failed to add Full-Speed configuration");
67+
return NULL;
68+
}
69+
/* doc configuration register end */
70+
71+
/* doc functions register start */
72+
err = usbd_register_all_classes(&app_usbd, USBD_SPEED_FS, 1, NULL);
73+
if (err) {
74+
LOG_ERR("Failed to add register classes");
75+
return NULL;
76+
}
77+
/* doc functions register end */
78+
79+
/* Always use class code information from Interface Descriptors */
80+
if (IS_ENABLED(CONFIG_USBD_CDC_ACM_CLASS) ||
81+
IS_ENABLED(CONFIG_USBD_CDC_ECM_CLASS) ||
82+
IS_ENABLED(CONFIG_USBD_CDC_NCM_CLASS) ||
83+
IS_ENABLED(CONFIG_USBD_MIDI2_CLASS) ||
84+
IS_ENABLED(CONFIG_USBD_AUDIO2_CLASS) ||
85+
IS_ENABLED(CONFIG_USBD_VIDEO_CLASS)) {
86+
/*
87+
* Class with multiple interfaces have an Interface
88+
* Association Descriptor available, use an appropriate triple
89+
* to indicate it.
90+
*/
91+
usbd_device_set_code_triple(&app_usbd, USBD_SPEED_FS,
92+
USB_BCC_MISCELLANEOUS, 0x02, 0x01);
93+
} else {
94+
usbd_device_set_code_triple(&app_usbd, USBD_SPEED_FS, 0, 0, 0);
95+
}
96+
97+
usbd_self_powered(&app_usbd, attributes & USB_SCD_SELF_POWERED);
98+
99+
/* doc device init start */
100+
err = usbd_init(&app_usbd);
101+
if (err) {
102+
LOG_ERR("Failed to initialize device support");
103+
return NULL;
104+
}
105+
/* doc device init end */
106+
107+
return &app_usbd;
108+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/device.h>
8+
#include <zephyr/usb/usbh.h>
9+
10+
#include <zephyr/logging/log.h>
11+
LOG_MODULE_REGISTER(usbh_app_config);
12+
13+
USBH_CONTROLLER_DEFINE(app_usbh,
14+
DEVICE_DT_GET(DT_NODELABEL(virtual_uhc0)));
15+
16+
struct usbh_contex *app_usbh_init_controller(void)
17+
{
18+
int err;
19+
20+
err = usbh_init(&app_usbh);
21+
if (err) {
22+
LOG_ERR("Failed to initialize host support");
23+
return NULL;
24+
}
25+
26+
return &app_usbh;
27+
}

0 commit comments

Comments
 (0)