基于HPM6750实现一个UVC和MSC的符合类设备
文章目录
- 1、USB主从协议栈
- 2、MSC类理论学习
- 3、UVC类理论学习
- 4、UVC和MSC符合类设备
- 5、实验现象
- 6、存在问题
- 总结
学习目标:
-
了解HPM6750的USB协议栈
-
去看HPM6750的USB协议栈的源代码
-
尝试实现UCV(视频类的)
-
尝试实现MSC(存储类)(虚拟U盘)
-
两者进行结合
-
UCV(视频类)
- 输出USB摄像头
- MSC(大容量存储类)
- 输出USB U盘
UVC(USB Video Class)设备驱动程序支持JPEG帧流传输到USB主机。用户可以通过回调函数将任何设备封装成符合UVC标准的设备。
MSC (USB MSC U盘)
最理想的输出:板子摄像头采集到数据之后存到sd卡
先跑demo然后再看理论,不要一开始就直接上理论,这个很重要
1、USB主从协议栈
注: 截至CherryUSB协议栈
描述符一个usb设备有多个设备描述符
驱动框架
设备API在usb_dc.h
-
👌需要实现的设备框架
👍usbd_set_address(设备地址,每一个设备都有设备地址)
#include "usb_dc.h" uint8_t dev_addr = 0; int usbd_set_address(const uint8_t addr) { /* 填写设备地址寄存器 */ /* 立刻设置还是延时设置 */ if(addr == 0) { /* xxxx */ } dev_addr =addr; /* setup in */ } /* 设置端点 */ int usbd_ep_open(const struct usbd_endpoint_cfg *ep_cfg) { /* 设置端点传输type */ /* 设置端点的地址 */ /* 设置端点mps */ /*主要是in和out事务*/ } /* 关闭端点 */ int usbd_ep_close(const uint8_t ep) { /* 实现收发使能 */ } /* 根据方向设置到寄存器中的stall标志位 */ int usbd_ep_set_stall(const uint8_t ep) { /* 根据方向设置到寄存器中的stall标志位 */ } int usbd_ep_clear_stall(const uint8_t ep) { /* 根据方向设置到寄存器中的stall剔除标志位 开启out端点使能 */ } int usbd_ep_is_stall() { /* 读stall寄存器然后设置到stall里面去 */ /* stalled = get_stall_state(); */ } int usbd_ep_write(const uint8_t ep,const uint8_t *data, uint32_t data_len, uint32_t *ret_bytes) { /* 需要判断 */ if(ep & 0x80 !=0x80) { return -1; } ..... } int usbd_ep_read(const uint8_t ep,uint8_t *data,uint32_t max_data_len,uint32_t *read_bytes) { } /* write 先填充之后在发送 */ /* 先使能之后才可以发送 一般使能都在open这边 */ /* 硬件需要实现的一些接口 */ int usbd_dc_init() { /* 开启usb时钟 */ /* 配置usb引脚 */ /* 开时钟 清除usb中断、寄存器 */ /* 配置一些基础的属性 */ /* 配置fifo*/ /* 开启usb中断 置为,rest ep中断 */ /* 开总中断 */ } int usbd_deinit() { /* */ } void USB_IRQ() ....... /* 中断回调函数 */ void subd_irq_callback(uint8_t event,void *args) { /* */ } /* 当usb调用中断了之后,协议栈就开始运行了 */
2、MSC类理论学习
- 调用msc_ram_init配置msc描述符并初始化usb硬件
- 因为msc有一个接口,所以需要调用usbd_add_interface接口 1次
- msc中的端点的数据流是cherryusb协议栈这边管理的,所以不需要用户注册端点的回调函数。同理usbd_configure_done_callback也不需要空函数即可。
参考连接:
git clone https://github.com/cherry-embedded/CherryUSB/blob/master/docs/source/tools
参考官网的demo移植出MSC(U盘类)(2024.8.15)
示例代码
移植好cherryusb(官网已经移植好了这里是demo)
main.c
/*
* Copyright (c) 2022 HPMicro
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <stdio.h>
#include "board.h"
#include "hpm_debug_console.h"
#include "usb_config.h"
#define LED_FLASH_PERIOD_IN_MS 300
extern void msc_ram_init(uint8_t busid, uint32_t reg_base);
int main(void)
{
board_init();
board_init_led_pins();
board_init_usb_pins(); /* usb引脚初始化 */
intc_set_irq_priority(CONFIG_HPM_USBD_IRQn, 2); /* 设置中断优先级 */
board_timer_create(LED_FLASH_PERIOD_IN_MS, board_led_toggle); /* 反转板载RGB灯 */
printf("cherry usb msc_ram sample.\n");
/*
* 实现模拟U盘
* msc_ram_init 这个需要配置描述符并初始化USB硬件外设
* 因为msc有一个接口,所以需要调用usb_add_interface 1次
*
*/
msc_ram_init(0, CONFIG_HPM_USBD_BASE); /* usb0的基地址 0xF2020000UL */
while (1) {
}
return 0;
}
msc_ram.c 这个文件是使用ram当作u盘来使用
msc_ram.c
/*
* Copyright (c) 2022-2023 HPMicro
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include "usbd_core.h"
#include "usbd_msc.h"
#define MSC_IN_EP 0x81
#define MSC_OUT_EP 0x02
#define USB_CONFIG_SIZE (9 + MSC_DESCRIPTOR_LEN)
static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0200, 0x01),
};
static const uint8_t config_descriptor_hs[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
MSC_DESCRIPTOR_INIT(0x00, MSC_OUT_EP, MSC_IN_EP, USB_BULK_EP_MPS_HS, 0x02),
};
static const uint8_t config_descriptor_fs[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
MSC_DESCRIPTOR_INIT(0x00, MSC_OUT_EP, MSC_IN_EP, USB_BULK_EP_MPS_FS, 0x02),
};
static const uint8_t device_quality_descriptor[] = {
USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, 0x01),
};
static const uint8_t other_speed_config_descriptor_hs[] = {
USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
MSC_DESCRIPTOR_INIT(0x00, MSC_OUT_EP, MSC_IN_EP, USB_BULK_EP_MPS_FS, 0x02),
};
static const uint8_t other_speed_config_descriptor_fs[] = {
USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
MSC_DESCRIPTOR_INIT(0x00, MSC_OUT_EP, MSC_IN_EP, USB_BULK_EP_MPS_HS, 0x02),
};
static const char *string_descriptors[] = {
(const char[]){ 0x09, 0x04 }, /* Langid */
"HPMicro", /* Manufacturer */
"HPMicro MSC DEMO", /* Product */
"2024051701", /* Serial Number */
};
static const uint8_t *device_descriptor_callback(uint8_t speed)
{
(void)speed;
return device_descriptor;
}
static const uint8_t *config_descriptor_callback(uint8_t speed)
{
if (speed == USB_SPEED_HIGH) {
return config_descriptor_hs;
} else if (speed == USB_SPEED_FULL) {
return config_descriptor_fs;
} else {
return NULL;
}
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
{
(void)speed;
return device_quality_descriptor;
}
static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
{
if (speed == USB_SPEED_HIGH) {
return other_speed_config_descriptor_hs;
} else if (speed == USB_SPEED_FULL) {
return other_speed_config_descriptor_fs;
} else {
return NULL;
}
}
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
{
(void)speed;
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
return NULL;
}
return string_descriptors[index];
}
const struct usb_descriptor msc_ram_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
.other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback,
};
static void usbd_event_handler(uint8_t busid, uint8_t event)
{
(void)busid;
switch (event) {
case USBD_EVENT_RESET:
break;
case USBD_EVENT_CONNECTED:
break;
case USBD_EVENT_DISCONNECTED:
break;
case USBD_EVENT_RESUME:
break;
case USBD_EVENT_SUSPEND:
break;
case USBD_EVENT_CONFIGURED:
break;
case USBD_EVENT_SET_REMOTE_WAKEUP:
break;
case USBD_EVENT_CLR_REMOTE_WAKEUP:
break;
default:
break;
}
}
/* Some MCU doesn't have enough 8KB SRAM to store the whole disk
* We will use Flash as read-only disk with board that has
* CFG_EXAMPLE_MSC_READONLY defined
*/
#define README_CONTENTS \
"This is CherryUSB's MassStorage Class demo.\r\n"
enum {
DISK_BLOCK_NUM = 64, /* 8KB is the smallest size that windows allow to mount, set to 32KB */
DISK_BLOCK_SIZE = 512
};
/*
64
512
*/
#ifdef CFG_EXAMPLE_MSC_READONLY
const
#endif
uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = {
/*------------- Block0: Boot Sector -------------*/
/* byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = DISK_BLOCK_NUM;
* sector_per_cluster = 1; reserved_sectors = 1;
* fat_num = 1; fat12_root_entry_num = 16;
* sector_per_fat = 1; sector_per_track = 1; head_num = 1; hidden_sectors = 0;
* drive_number = 0x80; media_type = 0xf8; extended_boot_signature = 0x29;
* filesystem_type = "FAT12 "; volume_serial_number = 0x1234; volume_label = "Hpmicro MSC";
*/
/* FAT magic code at offset 510-511 */
{
0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x01, 0x01, 0x00,
0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'H', 'P', 'M', 'i', 'c',
'r', 'o', ' ', 'M', 'S', 'C', 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00,
/* Zero up to 2 last bytes of FAT magic code */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA
},
/*------------- Block1: FAT12 Table -------------*/
{
0xF8, 0xFF, 0xFF, 0xFF, 0x0F /* first 2 entries must be F8FF, third entry is cluster end of readme file */
},
/*------------- Block2: Root Directory -------------*/
{
/* first entry is volume label */
'H', 'P', 'M', 'i', 'c', 'r', 'o', ' ', 'M', 'S', 'C', 0x08, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* second entry is readme file */
'R', 'E', 'A', 'D', 'M', 'E', ' ', ' ', 'T', 'X', 'T', 0x20, 0x00, 0xC6, 0x52, 0x6D,
0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, 0x02, 0x00,
sizeof(README_CONTENTS)-1, 0x00, 0x00, 0x00 /* readme's files size (4 Bytes) */
},
/*------------- Block3: Readme Content -------------*/
README_CONTENTS
};
void usbd_msc_get_cap(uint8_t busid, uint8_t lun, uint32_t *block_num, uint32_t *block_size)
{
(void)busid;
(void)lun;
*block_num = DISK_BLOCK_NUM;
*block_size = DISK_BLOCK_SIZE;
}
int usbd_msc_sector_read(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length)
{
(void)busid;
(void)lun;
if (sector < DISK_BLOCK_NUM)
memcpy(buffer, &msc_disk[sector][0], length);
return 0;
}
int usbd_msc_sector_write(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length)
{
(void)busid;
(void)lun;
if (sector < DISK_BLOCK_NUM)
memcpy(&msc_disk[sector][0], buffer, length);
return 0;
}
/* function ------------------------------------------------------------------*/
/**
* @brief msc ram init
* @pre none
* @param[in] none
* @retval none
*/
struct usbd_interface intf0;
void msc_ram_init(uint8_t busid, uint32_t reg_base)
{
/* 注册设备 */
usbd_desc_register(busid, &msc_ram_descriptor);
/* 添加接口 */
usbd_add_interface(busid, usbd_msc_init_intf(busid, &intf0, MSC_OUT_EP, MSC_IN_EP));
/* USB初始化 */
usbd_initialize(busid, reg_base, usbd_event_handler);
}
3、UVC类理论学习
来源cherryusb指导手册
UVC设备都是多interface接口(组合类设备)UVC最少有两个interface接口:
- videoCotrl(VC)
- VideoStream(VS)
学习路线参考sdk的demo
移植好ov5640摄像头dvp(2024.8.19)
成功添加video class到msc工程并成功编译无报错。 2024.8.23
待解决:
- ucv枚举(2024.8.23)
- ov5640摄像头将数据传输到pc端(2024.8.23)
已解决:
- uvc枚举成功,在电脑端已经找到设备(2024.8.27)
这可能是我们最常见的UVC设备,在实际开发中VCinterface用于进行配置、操控、设置UVC设备进入不同的状态。而VS interface则负责视频数据流的传输;完整的UVC依赖VCS,VC interface的配合才能实现。
参考 cherryUSB video template 的c文件。
示例代码 和硬件型号hpm6750evkmini
usbd_uvc_template.c
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbd_core.h"
#include "usbd_video.h"
#include "pic_data.h"
#define VIDEO_IN_EP 0x81
#ifdef CONFIG_USB_HS
#define MAX_PAYLOAD_SIZE 1024 // for high speed with one transcations every one micro frame
#define VIDEO_PACKET_SIZE (unsigned int)(((MAX_PAYLOAD_SIZE / 1)) | (0x00 << 11))
// #define MAX_PAYLOAD_SIZE 2048 // for high speed with two transcations every one micro frame
// #define VIDEO_PACKET_SIZE (unsigned int)(((MAX_PAYLOAD_SIZE / 2)) | (0x01 << 11))
// #define MAX_PAYLOAD_SIZE 3072 // for high speed with three transcations every one micro frame
// #define VIDEO_PACKET_SIZE (unsigned int)(((MAX_PAYLOAD_SIZE / 3)) | (0x02 << 11))
#else
#define MAX_PAYLOAD_SIZE 1020
#define VIDEO_PACKET_SIZE (unsigned int)(((MAX_PAYLOAD_SIZE / 1)) | (0x00 << 11))
#endif
#define WIDTH (unsigned int)(640)
#define HEIGHT (unsigned int)(480)
#define CAM_FPS (30)
#define INTERVAL (unsigned long)(10000000 / CAM_FPS)
#define MIN_BIT_RATE (unsigned long)(WIDTH * HEIGHT * 16 * CAM_FPS) //16 bit
#define MAX_BIT_RATE (unsigned long)(WIDTH * HEIGHT * 16 * CAM_FPS)
#define MAX_FRAME_SIZE (unsigned long)(WIDTH * HEIGHT * 2)
#define USB_VIDEO_DESC_SIZ (unsigned long)(9 + \
8 + \
9 + \
13 + \
18 + \
9 + \
12 + \
9 + \
14 + \
11 + \
30 + \
9 + \
7)
#define VC_TERMINAL_SIZ (unsigned int)(13 + 18 + 12 + 9)
#define VS_HEADER_SIZ (unsigned int)(13 + 1 + 11 + 30)
#define USBD_VID 0xffff
#define USBD_PID 0xffff
#define USBD_MAX_POWER 100
#define USBD_LANGID_STRING 1033
const uint8_t video_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xef, 0x02, 0x01, USBD_VID, USBD_PID, 0x0001, 0x01),
USB_CONFIG_DESCRIPTOR_INIT(USB_VIDEO_DESC_SIZ, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
VIDEO_VC_DESCRIPTOR_INIT(0x00, 0, 0x0100, VC_TERMINAL_SIZ, 48000000, 0x02),
VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x00, 0x00),
VIDEO_VS_HEADER_DESCRIPTOR_INIT(0x01, VS_HEADER_SIZ, VIDEO_IN_EP, 0x00),
VIDEO_VS_FORMAT_MJPEG_DESCRIPTOR_INIT(0x01, 0x01),
VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_INIT(0x01, WIDTH, HEIGHT, MIN_BIT_RATE, MAX_BIT_RATE, MAX_FRAME_SIZE, DBVAL(INTERVAL), 0x01, DBVAL(INTERVAL)),
VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x01, 0x01),
/* 1.2.2.2 Standard VideoStream Isochronous Video Data Endpoint Descriptor */
0x07, /* bLength */
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: ENDPOINT */
0x81, /* bEndpointAddress: IN endpoint 2 */
0x01, /* bmAttributes: Isochronous transfer type. Asynchronous synchronization type. */
WBVAL(VIDEO_PACKET_SIZE), /* wMaxPacketSize */
0x01, /* bInterval: One frame interval */
///
/// string0 descriptor
///
USB_LANGID_INIT(USBD_LANGID_STRING),
///
/// string1 descriptor
///
0x14, /* bLength */
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
'C', 0x00, /* wcChar0 */
'h', 0x00, /* wcChar1 */
'e', 0x00, /* wcChar2 */
'r', 0x00, /* wcChar3 */
'r', 0x00, /* wcChar4 */
'y', 0x00, /* wcChar5 */
'U', 0x00, /* wcChar6 */
'S', 0x00, /* wcChar7 */
'B', 0x00, /* wcChar8 */
///
/// string2 descriptor
///
0x26, /* bLength */
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
'C', 0x00, /* wcChar0 */
'h', 0x00, /* wcChar1 */
'e', 0x00, /* wcChar2 */
'r', 0x00, /* wcChar3 */
'r', 0x00, /* wcChar4 */
'y', 0x00, /* wcChar5 */
'U', 0x00, /* wcChar6 */
'S', 0x00, /* wcChar7 */
'B', 0x00, /* wcChar8 */
' ', 0x00, /* wcChar9 */
'U', 0x00, /* wcChar10 */
'V', 0x00, /* wcChar11 */
'C', 0x00, /* wcChar12 */
' ', 0x00, /* wcChar13 */
'D', 0x00, /* wcChar14 */
'E', 0x00, /* wcChar15 */
'M', 0x00, /* wcChar16 */
'O', 0x00, /* wcChar17 */
///
/// string3 descriptor
///
0x16, /* bLength */
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
'2', 0x00, /* wcChar0 */
'0', 0x00, /* wcChar1 */
'2', 0x00, /* wcChar2 */
'1', 0x00, /* wcChar3 */
'0', 0x00, /* wcChar4 */
'3', 0x00, /* wcChar5 */
'1', 0x00, /* wcChar6 */
'0', 0x00, /* wcChar7 */
'0', 0x00, /* wcChar8 */
'0', 0x00, /* wcChar9 */
#ifdef CONFIG_USB_HS
///
/// device qualifier descriptor
///
0x0a,
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
0x00,
0x02,
0x00,
0x00,
0x00,
0x40,
0x01,
0x00,
#endif
0x00
};
/******************************************************************/
#if 1
/* 设备描述符 */
static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xef, 0x02, 0x01, USBD_VID, USBD_PID, 0x0001, 0x01)
};
/* 配置描述符 */
static const uint8_t config_descriptor[] = {
//USB_CONFIG_DESCRIPTOR_INIT(USB_VIDEO_DESC_SIZ, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
USB_CONFIG_DESCRIPTOR_INIT(USB_VIDEO_DESC_SIZ, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
VIDEO_VC_DESCRIPTOR_INIT(0x00, 0, 0x0100, VC_TERMINAL_SIZ, 48000000, 0x02),
VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x00, 0x00),
VIDEO_VS_HEADER_DESCRIPTOR_INIT(0x01, VS_HEADER_SIZ, VIDEO_IN_EP, 0x00),
VIDEO_VS_FORMAT_MJPEG_DESCRIPTOR_INIT(0x01, 0x01),
VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_INIT(0x01, WIDTH, HEIGHT, MIN_BIT_RATE, MAX_BIT_RATE, MAX_FRAME_SIZE, DBVAL(INTERVAL), 0x01, DBVAL(INTERVAL)),
VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x01, 0x01),
/* 1.2.2.2 Standard VideoStream Isochronous Video Data Endpoint Descriptor */
0x07, /* bLength */
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: ENDPOINT */
0x81, /* bEndpointAddress: IN endpoint 2 */
0x01, /* bmAttributes: Isochronous transfer type. Asynchronous synchronization type. */
WBVAL(VIDEO_PACKET_SIZE), /* wMaxPacketSize */
0x01,
};
/* other 配置描述符 */
static const uint8_t other_speed_config_descriptor[] = {
USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_VIDEO_DESC_SIZ, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
VIDEO_VC_DESCRIPTOR_INIT(0x00, 0, 0x0100, VC_TERMINAL_SIZ, 48000000, 0x02),
VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x00, 0x00),
VIDEO_VS_HEADER_DESCRIPTOR_INIT(0x01, VS_HEADER_SIZ, VIDEO_IN_EP, 0x00),
VIDEO_VS_FORMAT_MJPEG_DESCRIPTOR_INIT(0x01, 0x01),
VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_INIT(0x01, WIDTH, HEIGHT, MIN_BIT_RATE, MAX_BIT_RATE, MAX_FRAME_SIZE, DBVAL(INTERVAL), 0x01, DBVAL(INTERVAL)),
VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x01, 0x01),
/* 1.2.2.2 Standard VideoStream Isochronous Video Data Endpoint Descriptor */
0x07, /* bLength */
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: ENDPOINT */
0x81, /* bEndpointAddress: IN endpoint 2 */
0x01, /* bmAttributes: Isochronous transfer type. Asynchronous synchronization type. */
WBVAL(VIDEO_PACKET_SIZE), /* wMaxPacketSize */
0x01,
};
/* 质量描述符 */
static const uint8_t device_quality_descriptor[] = {
USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, 0x01),
};
/* 设备描述符回调 */
static const uint8_t *device_descriptor_callback(uint8_t speed) {
(void)speed;
return device_descriptor;
};
/* 配置描述符 */
static const uint8_t *config_descriptor_callback(uint8_t speed) {
(void)speed;
return config_descriptor;
};
/* 质量描述符 */
static const uint8_t *device_quality_descriptor_callback(uint8_t speed) {
(void)speed;
return device_quality_descriptor;
};
/* 其它速度配置描述符 */
static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed) {
(void)speed;
return other_speed_config_descriptor;
};
/* 字符描述符 */
static const char *string_descriptors[] = {
(const char[]){ 0x09, 0x04 }, /* Langid */
"HPMicro", /* Manufacturer */
"HPMicro UVC DEMO", /* Product */
"2024031000", /* Serial Number */
};
/* 字符描述符回调 */
static const char *string_descriptor_callback(uint8_t speed, uint8_t index) {
(void)speed;
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
return NULL;
}
return string_descriptors[index];
};
/*!<结构体>*/
const struct usb_descriptor uvc_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
.other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback,
};
#endif /* 0 */
/******************************************************************/
volatile bool tx_flag = 0;
volatile bool iso_tx_busy = false;
static void usbd_event_handler(uint8_t busid, uint8_t event)
{
switch (event) {
case USBD_EVENT_RESET:
break;
case USBD_EVENT_CONNECTED:
break;
case USBD_EVENT_DISCONNECTED:
break;
case USBD_EVENT_RESUME:
break;
case USBD_EVENT_SUSPEND:
break;
case USBD_EVENT_CONFIGURED:
tx_flag = 0;
iso_tx_busy = false;
break;
case USBD_EVENT_SET_REMOTE_WAKEUP:
break;
case USBD_EVENT_CLR_REMOTE_WAKEUP:
break;
default:
break;
}
}
void usbd_video_open(uint8_t busid, uint8_t intf)
{
tx_flag = 1;
USB_LOG_RAW("OPEN\r\n");
iso_tx_busy = false;
}
void usbd_video_close(uint8_t busid, uint8_t intf)
{
USB_LOG_RAW("CLOSE\r\n");
tx_flag = 0;
iso_tx_busy = false;
}
void usbd_video_iso_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
USB_LOG_RAW("actual in len:%d\r\n", nbytes);
iso_tx_busy = false;
}
static struct usbd_endpoint video_in_ep = {
.ep_cb = usbd_video_iso_callback,
.ep_addr = VIDEO_IN_EP
};
struct usbd_interface intf0;
struct usbd_interface intf1;
void video_init(uint8_t busid, uint32_t reg_base)
{
//usbd_desc_register(busid, video_descriptor);
usbd_desc_register(busid, &uvc_descriptor);
usbd_add_interface(busid, usbd_video_init_intf(busid, &intf0, INTERVAL, MAX_FRAME_SIZE, MAX_PAYLOAD_SIZE));
usbd_add_interface(busid, usbd_video_init_intf(busid, &intf1, INTERVAL, MAX_FRAME_SIZE, MAX_PAYLOAD_SIZE));
usbd_add_endpoint(busid, &video_in_ep);
usbd_initialize(busid, reg_base, usbd_event_handler);
}
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t packet_buffer[10 * 1024];
void video_test(uint8_t busid)
{
uint32_t out_len;
uint32_t packets;
memset(packet_buffer, 0, 10 * 1024);
while (1) {
if (tx_flag) {
packets = usbd_video_mjpeg_payload_fill(busid, (uint8_t *)jpeg_data, sizeof(jpeg_data), packet_buffer, &out_len);
#if 0
iso_tx_busy = true;
usbd_ep_start_write(busid, VIDEO_IN_EP, packet_buffer, out_len);
while (iso_tx_busy) {
if (tx_flag == 0) {
break;
}
}
#else
/* dwc2 must use this method */
for (uint32_t i = 0; i < packets; i++) {
if (i == (packets - 1)) {
iso_tx_busy = true;
usbd_ep_start_write(busid, VIDEO_IN_EP, &packet_buffer[i * MAX_PAYLOAD_SIZE], out_len - (packets - 1) * MAX_PAYLOAD_SIZE);
while (iso_tx_busy) {
if (tx_flag == 0) {
break;
}
}
} else {
iso_tx_busy = true;
usbd_ep_start_write(busid, VIDEO_IN_EP, &packet_buffer[i * MAX_PAYLOAD_SIZE], MAX_PAYLOAD_SIZE);
while (iso_tx_busy) {
if (tx_flag == 0) {
break;
}
}
}
}
#endif
}
}
}
4、UVC和MSC符合类设备
问题:
-
进行组合之后枚举不成功(2024.8.28)
-
排除空间的问题
-
将uvc和msc类进行结合
Composite_uvc_msc.c
/*********************************************************************/
#include "usbd_core.h"
#include "usbd_video.h"
#include "usbd_msc.h"
#include "pic_data.h"
#define VIDEO_IN_EP 0x81
#define MSC_IN_EP 0x84
#define MSC_OUT_EP 0x05
#define USB_CONFIG_SIZE (unsigned long) 32
#define MAX_PAYLOAD_SIZE 1024 // for high speed with one transcations every one micro frame
#define VIDEO_PACKET_SIZE (unsigned int)(((MAX_PAYLOAD_SIZE / 1)) | (0x00 << 11))
#define WIDTH (unsigned int)(640)
#define HEIGHT (unsigned int)(480)
#define CAM_FPS (30)
#define INTERVAL (unsigned long)(10000000 / CAM_FPS)
#define MIN_BIT_RATE (unsigned long)(WIDTH * HEIGHT * 16 * CAM_FPS) //16 bit
#define MAX_BIT_RATE (unsigned long)(WIDTH * HEIGHT * 16 * CAM_FPS)
#define MAX_FRAME_SIZE (unsigned long)(WIDTH * HEIGHT * 2)
#define USB_VIDEO_DESC_SIZ (unsigned long)(9 + \
8 + \
9 + \
13 + \
18 + \
9 + \
12 + \
9 + \
14 + \
11 + \
30 + \
9 + \
7)
#define USBD_SIZE (USB_CONFIG_SIZE + USB_VIDEO_DESC_SIZ) //size 是全部描述符的相加
#define VC_TERMINAL_SIZ (unsigned int)(13 + 18 + 12 + 9)
#define VS_HEADER_SIZ (unsigned int)(13 + 1 + 11 + 30)
#define USBD_LANGID_STRING 1033
/******************************************************************/
#if 1
/* 设备描述符 */
static const uint8_t device_descriptor[] = {
//USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xef, 0x02, 0x01, USBD_VID, USBD_PID, 0x0001, 0x01),
// USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0200, 0x01),
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xef, 0x02, 0x01, USBD_VID, USBD_PID, 0x0200, 0x01),
};
/* 配置描述符 */
static const uint8_t config_descriptor[] = {
USB_CONFIG_DESCRIPTOR_INIT(USBD_SIZE, 0x03, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
VIDEO_VC_DESCRIPTOR_INIT(0x00, 0, 0x0100, VC_TERMINAL_SIZ, 48000000, 0x02),
VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x00, 0x00),
VIDEO_VS_HEADER_DESCRIPTOR_INIT(0x01, VS_HEADER_SIZ, VIDEO_IN_EP, 0x00),
VIDEO_VS_FORMAT_MJPEG_DESCRIPTOR_INIT(0x01, 0x01),
VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_INIT(0x01, WIDTH, HEIGHT, MIN_BIT_RATE, MAX_BIT_RATE, MAX_FRAME_SIZE, DBVAL(INTERVAL), 0x01, DBVAL(INTERVAL)),
VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x01, 0x01),
/* 1.2.2.2 Standard VideoStream Isochronous Video Data Endpoint Descriptor */
0x07, /* bLength */
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: ENDPOINT */
0x81, /* bEndpointAddress: IN endpoint 2 */
0x01, /* bmAttributes: Isochronous transfer type. Asynchronous synchronization type. */
WBVAL(VIDEO_PACKET_SIZE), /* wMaxPacketSize */
0x01,
MSC_DESCRIPTOR_INIT(0x02, MSC_OUT_EP, MSC_IN_EP, 512, 0x02),
};
/* other 配置描述符 */
static const uint8_t other_speed_config_descriptor[] = {
USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USBD_SIZE, 0x03, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
VIDEO_VC_DESCRIPTOR_INIT(0x00, 0, 0x0100, VC_TERMINAL_SIZ, 48000000, 0x02),
VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x00, 0x00),
VIDEO_VS_HEADER_DESCRIPTOR_INIT(0x01, VS_HEADER_SIZ, VIDEO_IN_EP, 0x00),
VIDEO_VS_FORMAT_MJPEG_DESCRIPTOR_INIT(0x01, 0x01),
VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_INIT(0x01, WIDTH, HEIGHT, MIN_BIT_RATE, MAX_BIT_RATE, MAX_FRAME_SIZE, DBVAL(INTERVAL), 0x01, DBVAL(INTERVAL)),
VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x01, 0x01),
/* 1.2.2.2 Standard VideoStream Isochronous Video Data Endpoint Descriptor */
0x07, /* bLength */
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: ENDPOINT */
0x81, /* bEndpointAddress: IN endpoint 2 */
0x01, /* bmAttributes: Isochronous transfer type. Asynchronous synchronization type. */
WBVAL(VIDEO_PACKET_SIZE), /* wMaxPacketSize */
0x01,
MSC_DESCRIPTOR_INIT(0x02, MSC_OUT_EP, MSC_IN_EP, 512, 0x02),
};
/* 质量描述符 */
static const uint8_t device_quality_descriptor[] = {
USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, 0x01),
};
/* 设备描述符回调 */
static const uint8_t *device_descriptor_callback(uint8_t speed) {
(void)speed;
return device_descriptor;
};
/* 配置描述符 */
static const uint8_t *config_descriptor_callback(uint8_t speed) {
(void)speed;
return config_descriptor;
};
/* 质量描述符 */
static const uint8_t *device_quality_descriptor_callback(uint8_t speed) {
(void)speed;
return device_quality_descriptor;
};
/* 其它速度配置描述符 */
static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed) {
(void)speed;
return other_speed_config_descriptor;
};
/* 字符描述符 */
static const char *string_descriptors[] = {
(const char[]){ 0x09, 0x04 }, /* Langid */
"HPMicro", /* Manufacturer */
"HPMicro UVC DEMO", /* Product */
"2024031000", /* Serial Number */
};
/* 字符描述符回调 */
static const char *string_descriptor_callback(uint8_t speed, uint8_t index) {
(void)speed;
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
return NULL;
}
return string_descriptors[index];
};
/*!<结构体>*/
const struct usb_descriptor uvc_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
.other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback,
};
#endif /* 0 */
/******************************************************************/
volatile bool tx_flag = 0;
volatile bool iso_tx_busy = false;
static void usbd_event_handler(uint8_t busid, uint8_t event)
{
switch (event) {
case USBD_EVENT_RESET:
break;
case USBD_EVENT_CONNECTED:
break;
case USBD_EVENT_DISCONNECTED:
break;
case USBD_EVENT_RESUME:
break;
case USBD_EVENT_SUSPEND:
break;
case USBD_EVENT_CONFIGURED:
tx_flag = 0;
iso_tx_busy = false;
break;
case USBD_EVENT_SET_REMOTE_WAKEUP:
break;
case USBD_EVENT_CLR_REMOTE_WAKEUP:
break;
default:
break;
}
}
#if 1 //uvc
void usbd_video_open(uint8_t busid, uint8_t intf)
{
tx_flag = 1;
USB_LOG_RAW("OPEN\r\n");
iso_tx_busy = false;
}
void usbd_video_close(uint8_t busid, uint8_t intf)
{
USB_LOG_RAW("CLOSE\r\n");
tx_flag = 0;
iso_tx_busy = false;
}
void usbd_video_iso_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
USB_LOG_RAW("actual in len:%d\r\n", nbytes);
iso_tx_busy = false;
}
static struct usbd_endpoint video_in_ep = {
.ep_cb = usbd_video_iso_callback,
.ep_addr = VIDEO_IN_EP
};
#endif
/*****************************************************/
/* Some MCU doesn't have enough 8KB SRAM to store the whole disk
* We will use Flash as read-only disk with board that has
* CFG_EXAMPLE_MSC_READONLY defined
*/
#define README_CONTENTS \
"This is CherryUSB's MassStorage Class demo.\r\n"
enum {
DISK_BLOCK_NUM = 64, /* 8KB is the smallest size that windows allow to mount, set to 32KB */
DISK_BLOCK_SIZE = 512
};
/*
64
512
*/
#ifdef CFG_EXAMPLE_MSC_READONLY
const
#endif
uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = {
/*------------- Block0: Boot Sector -------------*/
/* byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = DISK_BLOCK_NUM;
* sector_per_cluster = 1; reserved_sectors = 1;
* fat_num = 1; fat12_root_entry_num = 16;
* sector_per_fat = 1; sector_per_track = 1; head_num = 1; hidden_sectors = 0;
* drive_number = 0x80; media_type = 0xf8; extended_boot_signature = 0x29;
* filesystem_type = "FAT12 "; volume_serial_number = 0x1234; volume_label = "Hpmicro MSC";
*/
/* FAT magic code at offset 510-511 */
{
0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x01, 0x01, 0x00,
0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'H', 'P', 'M', 'i', 'c',
'r', 'o', ' ', 'M', 'S', 'C', 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00,
/* Zero up to 2 last bytes of FAT magic code */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA
},
/*------------- Block1: FAT12 Table -------------*/
{
0xF8, 0xFF, 0xFF, 0xFF, 0x0F /* first 2 entries must be F8FF, third entry is cluster end of readme file */
},
/*------------- Block2: Root Directory -------------*/
{
/* first entry is volume label */
'H', 'P', 'M', 'i', 'c', 'r', 'o', ' ', 'M', 'S', 'C', 0x08, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* second entry is readme file */
'R', 'E', 'A', 'D', 'M', 'E', ' ', ' ', 'T', 'X', 'T', 0x20, 0x00, 0xC6, 0x52, 0x6D,
0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, 0x02, 0x00,
sizeof(README_CONTENTS)-1, 0x00, 0x00, 0x00 /* readme's files size (4 Bytes) */
},
/*------------- Block3: Readme Content -------------*/
README_CONTENTS
};
void usbd_msc_get_cap(uint8_t busid, uint8_t lun, uint32_t *block_num, uint32_t *block_size)
{
(void)busid;
(void)lun;
*block_num = DISK_BLOCK_NUM;
*block_size = DISK_BLOCK_SIZE;
}
int usbd_msc_sector_read(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length)
{
(void)busid;
(void)lun;
if (sector < DISK_BLOCK_NUM)
memcpy(buffer, &msc_disk[sector][0], length);
return 0;
}
int usbd_msc_sector_write(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length)
{
(void)busid;
(void)lun;
if (sector < DISK_BLOCK_NUM)
memcpy(&msc_disk[sector][0], buffer, length);
return 0;
}
/*****************************************************/
struct usbd_interface intf0;
struct usbd_interface intf1;
struct usbd_interface intf2;
struct usbd_interface intf3;
void cherryusb_composite_init(uint8_t busid, uint32_t reg_base)
{
//usbd_desc_register(busid, video_descriptor);
usbd_desc_register(busid, &uvc_descriptor);
usbd_add_interface(busid, usbd_video_init_intf(busid, &intf0, INTERVAL, MAX_FRAME_SIZE, MAX_PAYLOAD_SIZE));
usbd_add_interface(busid, usbd_video_init_intf(busid, &intf1, INTERVAL, MAX_FRAME_SIZE, MAX_PAYLOAD_SIZE));
usbd_add_endpoint(busid, &video_in_ep);
usbd_add_interface(busid, usbd_msc_init_intf(busid, &intf2, MSC_OUT_EP, MSC_IN_EP)); /* msc */
usbd_initialize(busid, reg_base, usbd_event_handler);
}
/*********************************************************************/
main.c
/*********************************************************************/
#define uvc 0
#define msc 0
#define composite 1
#include "usbd_core.h"
#include "usbd_video.h"
#include "usbd_msc.h"
#include "pic_data.h"
#define VIDEO_IN_EP 0x81
#define MSC_IN_EP 0x82
#define MSC_OUT_EP 0x02
#define USB_CONFIG_SIZE (unsigned long) 32
#define MAX_PAYLOAD_SIZE 1024 // for high speed with one transcations every one micro frame
#define VIDEO_PACKET_SIZE (unsigned int)(((MAX_PAYLOAD_SIZE / 1)) | (0x00 << 11))
#define WIDTH (unsigned int)(640)
#define HEIGHT (unsigned int)(480)
#define CAM_FPS (30)
#define INTERVAL (unsigned long)(10000000 / CAM_FPS)
#define MIN_BIT_RATE (unsigned long)(WIDTH * HEIGHT * 16 * CAM_FPS) //16 bit
#define MAX_BIT_RATE (unsigned long)(WIDTH * HEIGHT * 16 * CAM_FPS)
#define MAX_FRAME_SIZE (unsigned long)(WIDTH * HEIGHT * 2)
#define USB_VIDEO_DESC_SIZ (unsigned long)(9 + \
8 + \
9 + \
13 + \
18 + \
9 + \
12 + \
9 + \
14 + \
11 + \
30 + \
9 + \
7)
#define USBD_SIZE (USB_CONFIG_SIZE + USB_VIDEO_DESC_SIZ) //size 是全部描述符的相加
#define VC_TERMINAL_SIZ (unsigned int)(13 + 18 + 12 + 9)
#define VS_HEADER_SIZ (unsigned int)(13 + 1 + 11 + 30)
#define USBD_LANGID_STRING 1033
/******************************************************************/
#if 1
/* 设备描述符 */
static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xef, 0x02, 0x01, USBD_VID, USBD_PID, 0x0001, 0x01),
// USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0200, 0x01),
//USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xef, 0x02, 0x01, USBD_VID, USBD_PID, 0x0200, 0x01),
};
/* 配置描述符 */
static const uint8_t config_descriptor[] = {
#if uvc
USB_CONFIG_DESCRIPTOR_INIT(USB_VIDEO_DESC_SIZ, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
VIDEO_VC_DESCRIPTOR_INIT(0x00, 0, 0x0100, VC_TERMINAL_SIZ, 48000000, 0x02),
VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x00, 0x00),
VIDEO_VS_HEADER_DESCRIPTOR_INIT(0x01, VS_HEADER_SIZ, VIDEO_IN_EP, 0x00),
VIDEO_VS_FORMAT_MJPEG_DESCRIPTOR_INIT(0x01, 0x01),
VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_INIT(0x01, WIDTH, HEIGHT, MIN_BIT_RATE, MAX_BIT_RATE, MAX_FRAME_SIZE, DBVAL(INTERVAL), 0x01, DBVAL(INTERVAL)),
VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x01, 0x01),
/* 1.2.2.2 Standard VideoStream Isochronous Video Data Endpoint Descriptor */
0x07, /* bLength */
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: ENDPOINT */
0x81, /* bEndpointAddress: IN endpoint 2 */
0x01, /* bmAttributes: Isochronous transfer type. Asynchronous synchronization type. */
WBVAL(VIDEO_PACKET_SIZE), /* wMaxPacketSize */
0x01,
#endif /* uvc */
#if msc
USB_CONFIG_DESCRIPTOR_INIT(USBD_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
MSC_DESCRIPTOR_INIT(0x02, MSC_OUT_EP, MSC_IN_EP, 64, 0x02),
#endif /* msc */
#if composite
USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USBD_SIZE, 0x03, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
VIDEO_VC_DESCRIPTOR_INIT(0x00, 0, 0x0100, VC_TERMINAL_SIZ, 48000000, 0x02),
VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x00, 0x00),
VIDEO_VS_HEADER_DESCRIPTOR_INIT(0x01, VS_HEADER_SIZ, VIDEO_IN_EP, 0x00),
VIDEO_VS_FORMAT_MJPEG_DESCRIPTOR_INIT(0x01, 0x01),
VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_INIT(0x01, WIDTH, HEIGHT, MIN_BIT_RATE, MAX_BIT_RATE, MAX_FRAME_SIZE, DBVAL(INTERVAL), 0x01, DBVAL(INTERVAL)),
VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x01, 0x01),
MSC_DESCRIPTOR_INIT(0x02, MSC_OUT_EP, MSC_IN_EP, 512, 0x02),
/* 1.2.2.2 Standard VideoStream Isochronous Video Data Endpoint Descriptor */
0x07, /* bLength */
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: ENDPOINT */
0x81, /* bEndpointAddress: IN endpoint 2 */
0x01, /* bmAttributes: Isochronous transfer type. Asynchronous synchronization type. */
WBVAL(VIDEO_PACKET_SIZE), /* wMaxPacketSize */
0x01,
#endif /* composite */
};
/* other 配置描述符 */
static const uint8_t other_speed_config_descriptor[] = {
#if uvc /*uvc device */
USB_CONFIG_DESCRIPTOR_INIT(USB_VIDEO_DESC_SIZ, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
VIDEO_VC_DESCRIPTOR_INIT(0x00, 0, 0x0100, VC_TERMINAL_SIZ, 48000000, 0x02),
VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x00, 0x00),
VIDEO_VS_HEADER_DESCRIPTOR_INIT(0x01, VS_HEADER_SIZ, VIDEO_IN_EP, 0x00),
VIDEO_VS_FORMAT_MJPEG_DESCRIPTOR_INIT(0x01, 0x01),
VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_INIT(0x01, WIDTH, HEIGHT, MIN_BIT_RATE, MAX_BIT_RATE, MAX_FRAME_SIZE, DBVAL(INTERVAL), 0x01, DBVAL(INTERVAL)),
VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x01, 0x01),
/* 1.2.2.2 Standard VideoStream Isochronous Video Data Endpoint Descriptor */
0x07, /* bLength */
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: ENDPOINT */
0x81, /* bEndpointAddress: IN endpoint 2 */
0x01, /* bmAttributes: Isochronous transfer type. Asynchronous synchronization type. */
WBVAL(VIDEO_PACKET_SIZE), /* wMaxPacketSize */
0x01,
#endif /* uvc */
#if msc /* msc hight speed 64 */
USB_CONFIG_DESCRIPTOR_INIT(USBD_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
MSC_DESCRIPTOR_INIT(0x02, MSC_OUT_EP, MSC_IN_EP, 64, 0x02),
#endif /* msc */
#if composite /* uvc and msc composite */
USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USBD_SIZE, 0x03, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
VIDEO_VC_DESCRIPTOR_INIT(0x00, 0x00, 0x0100, VC_TERMINAL_SIZ, 48000000, 0x02),
VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x00, 0x00),
VIDEO_VS_HEADER_DESCRIPTOR_INIT(0x01, VS_HEADER_SIZ, VIDEO_IN_EP, 0x00),
VIDEO_VS_FORMAT_MJPEG_DESCRIPTOR_INIT(0x01, 0x01),
VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_INIT(0x01, WIDTH, HEIGHT, MIN_BIT_RATE, MAX_BIT_RATE, MAX_FRAME_SIZE, DBVAL(INTERVAL), 0x01, DBVAL(INTERVAL)),
VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x01, 0x01),
MSC_DESCRIPTOR_INIT(0x02, MSC_OUT_EP, MSC_IN_EP, 512, 0x02),
/* 1.2.2.2 Standard VideoStream Isochronous Video Data Endpoint Descriptor */
0x07, /* bLength */
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: ENDPOINT */
0x81, /* bEndpointAddress: IN endpoint 2 */
0x01, /* bmAttributes: Isochronous transfer type. Asynchronous synchronization type. */
WBVAL(VIDEO_PACKET_SIZE), /* wMaxPacketSize */
0x01,
#endif /* composite */
};
/* 质量描述符 */
static const uint8_t device_quality_descriptor[] = {
USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, 0x01),
};
/* 设备描述符回调 */
static const uint8_t *device_descriptor_callback(uint8_t speed) {
(void)speed;
return device_descriptor;
};
/* 配置描述符 */
static const uint8_t *config_descriptor_callback(uint8_t speed) {
(void)speed;
return config_descriptor;
};
/* 质量描述符 */
static const uint8_t *device_quality_descriptor_callback(uint8_t speed) {
(void)speed;
return device_quality_descriptor;
};
/* 其它速度配置描述符 */
static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed) {
(void)speed;
return other_speed_config_descriptor;
};
/* 字符描述符 */
static const char *string_descriptors[] = {
(const char[]){ 0x09, 0x04 }, /* Langid */
"HPMicro", /* Manufacturer */
"HPMicro UVC DEMO", /* Product */
"2024031000", /* Serial Number */
};
/* 字符描述符回调 */
static const char *string_descriptor_callback(uint8_t speed, uint8_t index) {
(void)speed;
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
return NULL;
}
return string_descriptors[index];
};
/*!<结构体>*/
const struct usb_descriptor uvc_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
.other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback,
};
#endif /* 0 */
/******************************************************************/
volatile bool tx_flag = 0;
volatile bool iso_tx_busy = false;
static void usbd_event_handler(uint8_t busid, uint8_t event)
{
switch (event) {
case USBD_EVENT_RESET:
break;
case USBD_EVENT_CONNECTED:
break;
case USBD_EVENT_DISCONNECTED:
break;
case USBD_EVENT_RESUME:
break;
case USBD_EVENT_SUSPEND:
break;
case USBD_EVENT_CONFIGURED:
tx_flag = 0;
iso_tx_busy = false;
break;
case USBD_EVENT_SET_REMOTE_WAKEUP:
break;
case USBD_EVENT_CLR_REMOTE_WAKEUP:
break;
default:
break;
}
}
#if 1 //uvc
void usbd_video_open(uint8_t busid, uint8_t intf)
{
tx_flag = 1;
USB_LOG_RAW("OPEN\r\n");
iso_tx_busy = false;
}
void usbd_video_close(uint8_t busid, uint8_t intf)
{
USB_LOG_RAW("CLOSE\r\n");
tx_flag = 0;
iso_tx_busy = false;
}
void usbd_video_iso_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
USB_LOG_RAW("actual in len:%d\r\n", nbytes);
iso_tx_busy = false;
}
static struct usbd_endpoint video_in_ep = {
.ep_cb = usbd_video_iso_callback,
.ep_addr = VIDEO_IN_EP
};
#endif
/*****************************************************/
/* Some MCU doesn't have enough 8KB SRAM to store the whole disk
* We will use Flash as read-only disk with board that has
* CFG_EXAMPLE_MSC_READONLY defined
*/
#define README_CONTENTS \
"This is CherryUSB's MassStorage Class demo.\r\n"
enum {
DISK_BLOCK_NUM = 64, /* 8KB is the smallest size that windows allow to mount, set to 32KB */
DISK_BLOCK_SIZE = 512
};
/*
64
512
*/
#ifdef CFG_EXAMPLE_MSC_READONLY
const
#endif
uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = {
/*------------- Block0: Boot Sector -------------*/
/* byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = DISK_BLOCK_NUM;
* sector_per_cluster = 1; reserved_sectors = 1;
* fat_num = 1; fat12_root_entry_num = 16;
* sector_per_fat = 1; sector_per_track = 1; head_num = 1; hidden_sectors = 0;
* drive_number = 0x80; media_type = 0xf8; extended_boot_signature = 0x29;
* filesystem_type = "FAT12 "; volume_serial_number = 0x1234; volume_label = "Hpmicro MSC";
*/
/* FAT magic code at offset 510-511 */
{
0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x01, 0x01, 0x00,
0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'H', 'P', 'M', 'i', 'c',
'r', 'o', ' ', 'M', 'S', 'C', 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00,
/* Zero up to 2 last bytes of FAT magic code */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA
},
/*------------- Block1: FAT12 Table -------------*/
{
0xF8, 0xFF, 0xFF, 0xFF, 0x0F /* first 2 entries must be F8FF, third entry is cluster end of readme file */
},
/*------------- Block2: Root Directory -------------*/
{
/* first entry is volume label */
'H', 'P', 'M', 'i', 'c', 'r', 'o', ' ', 'M', 'S', 'C', 0x08, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* second entry is readme file */
'R', 'E', 'A', 'D', 'M', 'E', ' ', ' ', 'T', 'X', 'T', 0x20, 0x00, 0xC6, 0x52, 0x6D,
0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, 0x02, 0x00,
sizeof(README_CONTENTS)-1, 0x00, 0x00, 0x00 /* readme's files size (4 Bytes) */
},
/*------------- Block3: Readme Content -------------*/
README_CONTENTS
};
void usbd_msc_get_cap(uint8_t busid, uint8_t lun, uint32_t *block_num, uint32_t *block_size)
{
(void)busid;
(void)lun;
*block_num = DISK_BLOCK_NUM;
*block_size = DISK_BLOCK_SIZE;
}
int usbd_msc_sector_read(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length)
{
(void)busid;
(void)lun;
if (sector < DISK_BLOCK_NUM)
memcpy(buffer, &msc_disk[sector][0], length);
return 0;
}
int usbd_msc_sector_write(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length)
{
(void)busid;
(void)lun;
if (sector < DISK_BLOCK_NUM)
memcpy(&msc_disk[sector][0], buffer, length);
return 0;
}
/*****************************************************/
struct usbd_interface intf0;
struct usbd_interface intf1;
struct usbd_interface intf2;
struct usbd_interface intf3;
void cherryusb_composite_init(uint8_t busid, uint32_t reg_base)
{
//usbd_desc_register(busid, video_descriptor);
usbd_desc_register(busid, &uvc_descriptor);
#if uvc /*ucv device */
usbd_add_interface(busid, usbd_video_init_intf(busid, &intf0, INTERVAL, MAX_FRAME_SIZE, MAX_PAYLOAD_SIZE));
usbd_add_interface(busid, usbd_video_init_intf(busid, &intf1, INTERVAL, MAX_FRAME_SIZE, MAX_PAYLOAD_SIZE));
usbd_add_endpoint(busid, &video_in_ep);
#endif /* uvc */
#if msc /* msc device */
usbd_add_interface(busid, usbd_msc_init_intf(busid, &intf2, MSC_OUT_EP, MSC_IN_EP)); /* msc */
#endif /*msc device */
#if composite /*msc and uvc device */
usbd_add_interface(busid, usbd_video_init_intf(busid, &intf0, INTERVAL, MAX_FRAME_SIZE, MAX_PAYLOAD_SIZE));
usbd_add_interface(busid, usbd_video_init_intf(busid, &intf1, INTERVAL, MAX_FRAME_SIZE, MAX_PAYLOAD_SIZE));
usbd_add_endpoint(busid, &video_in_ep);
usbd_add_interface(busid, usbd_msc_init_intf(busid, &intf2, MSC_OUT_EP, MSC_IN_EP)); /* msc */
#endif /*composite */
usbd_initialize(busid, reg_base, usbd_event_handler);
}
/*********************************************************************/
5、实验现象
如下图,成功枚举出uvc和msc的设备,两个设备均可用。
6、存在问题
- 进行复合类设备的时候描述符没有描述对,在uvc的后面不小心添加msc的描述符导致端点冲突了。
- 今后学习需要注意要细心一些。(2024.9.4)
总结
本章主要介绍了笔者在调试CherryUSB协议栈符合类设备的调试过程以及一些笔者的心得和笔记。