diff --git a/docs/source/api/api_config.rst b/docs/source/api/api_config.rst index d7754fd0..836d3d85 100644 --- a/docs/source/api/api_config.rst +++ b/docs/source/api/api_config.rst @@ -1,116 +1,11 @@ USB CONFIG 宏 ========================= +通用 CONFIG 宏 +--------------------- 设备相关 CONFIG 宏 --------------------- -.. code-block:: C - - /* USB DEVICE Configuration */ - /* core */ - #ifndef CONFIG_USBDEV_REQUEST_BUFFER_LEN - #define CONFIG_USBDEV_REQUEST_BUFFER_LEN 256 - #endif - - #ifndef CONFIG_USBDEV_DESC_CHECK - #define CONFIG_USBDEV_DESC_CHECK 0 - #endif - - #ifndef CONFIG_USBDEV_TEST_MODE - #define CONFIG_USBDEV_TEST_MODE 0 - #endif - - /* msc class */ - #ifndef CONFIG_USBDEV_MSC_MANUFACTURER_STRING - #define CONFIG_USBDEV_MSC_MANUFACTURER_STRING "" - #endif - - #ifndef CONFIG_USBDEV_MSC_PRODUCT_STRING - #define CONFIG_USBDEV_MSC_PRODUCT_STRING "" - #endif - - #ifndef CONFIG_USBDEV_MSC_VERSION_STRING - #define CONFIG_USBDEV_MSC_VERSION_STRING "0.01" - #endif - - /* audio class */ - #ifndef CONFIG_USBDEV_AUDIO_VERSION - #define CONFIG_USBDEV_AUDIO_VERSION 0x0100 - #endif - - #ifndef CONFIG_USBDEV_AUDIO_MAX_CHANNEL - #define CONFIG_USBDEV_AUDIO_MAX_CHANNEL 2 - #endif - - 主机相关 CONFIG 宏 --------------------- - -.. code-block:: C - - /* USB HOST Configuration */ - #ifndef CONFIG_USBHOST_RHPORTS - #define CONFIG_USBHOST_RHPORTS 1 - #endif - - #ifndef CONFIG_USBHOST_EHPORTS - #define CONFIG_USBHOST_EHPORTS 4 - #endif - - #ifndef CONFIG_USBHOST_PIPE_NUM - #define CONFIG_USBHOST_PIPE_NUM 10 - #endif - - #ifndef CONFIG_USBHOST_INTF_NUM - #define CONFIG_USBHOST_INTF_NUM 6 - #endif - - #ifndef CONFIG_USBHOST_EP_NUM - #define CONFIG_USBHOST_EP_NUM 4 - #endif - - #ifndef CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT - #define CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT 5000 - #endif - - #ifndef CONFIG_USBHOST_MSC_TIMEOUT - #define CONFIG_USBHOST_MSC_TIMEOUT 5000 - #endif - - #ifndef CONFIG_USBHOST_HPWORKQ_PRIO - #define CONFIG_USBHOST_HPWORKQ_PRIO 5 - #endif - #ifndef CONFIG_USBHOST_HPWORKQ_STACKSIZE - #define CONFIG_USBHOST_HPWORKQ_STACKSIZE 2048 - #endif - - #ifndef CONFIG_USBHOST_LPWORKQ_PRIO - #define CONFIG_USBHOST_LPWORKQ_PRIO 1 - #endif - #ifndef CONFIG_USBHOST_LPWORKQ_STACKSIZE - #define CONFIG_USBHOST_LPWORKQ_STACKSIZE 2048 - #endif - - #ifndef CONFIG_USBHOST_PSC_PRIO - #define CONFIG_USBHOST_PSC_PRIO 4 - #endif - #ifndef CONFIG_USBHOST_PSC_STACKSIZE - #define CONFIG_USBHOST_PSC_STACKSIZE 4096 - #endif - - #ifndef CONFIG_USBHOST_DEV_NAMELEN - #define CONFIG_USBHOST_DEV_NAMELEN 16 - #endif - - #define CONFIG_USBHOST_ASYNCH - //#define CONFIG_USBHOST_GET_STRING_DESC - - /* EHCI Configuration */ - #define CONFIG_USB_EHCI_HCCR_BASE (0x20072000) - #define CONFIG_USB_EHCI_HCOR_BASE (0x20072000 + 0x10) - #define CONFIG_USB_EHCI_QH_NUM (10) - #define CONFIG_USB_EHCI_QTD_NUM (10) - // #define CONFIG_USB_EHCI_INFO_ENABLE - #define CONFIG_USB_ECHI_HCOR_RESERVED_DISABLE - // #define CONFIG_USB_EHCI_CONFIGFLAG \ No newline at end of file diff --git a/docs/source/api/api_port.rst b/docs/source/api/api_port.rst index 1fe9716b..95be593d 100644 --- a/docs/source/api/api_port.rst +++ b/docs/source/api/api_port.rst @@ -121,7 +121,7 @@ usbd_ep_start_read - **ep** out 端点地址 - **data** 接收数据缓冲区 -- **data_len** 接收长度,原则上无限长,推荐 16K 字节以内 +- **data_len** 接收长度,原则上无限长,推荐 16K 字节以内,并且推荐是最大包长的整数倍 - **return** 返回 0 表示正确,其他表示错误 .. note:: 启动接收以后,以下两种情况,会进入传输完成中断:1、最后一包为短包;2、接收总长度等于 data_len @@ -218,8 +218,10 @@ usbh_submit_urb uint32_t actual_length; uint32_t timeout; int errorcode; + uint32_t num_of_iso_packets; usbh_complete_callback_t complete; void *arg; + struct usbh_iso_frame_packet iso_packet[]; }; - **pipe** 端点对应的 pipe 句柄 @@ -230,8 +232,10 @@ usbh_submit_urb - **actual_length** 实际传输长度 - **timeout** 传输超时时间,为 0 该函数则为非阻塞,可在中断中使用 - **errorcode** 错误码 +- **num_of_iso_packets** iso 帧或者微帧个数 - **complete** 传输完成回调函数 - **arg** 传输完成时携带的参数 +- **iso_packet** iso 数据包 `errorcode` 可以返回以下值: @@ -258,4 +262,20 @@ usbh_submit_urb * - EPIPE - 数据溢出 * - ESHUTDOWN - - 设备断开,传输中止 \ No newline at end of file + - 设备断开,传输中止 + +其中 `iso_packet` 结构体信息如下: + +.. code-block:: C + + struct usbh_iso_frame_packet { + uint8_t *transfer_buffer; + uint32_t transfer_buffer_length; + uint32_t actual_length; + int errorcode; + }; + +- **transfer_buffer** 传输的数据缓冲区 +- **transfer_buffer_length** 传输长度 +- **actual_length** 实际传输长度 +- **errorcode** 错误码 \ No newline at end of file diff --git a/docs/source/class/class_audio.rst b/docs/source/class/class_audio.rst index a9f00098..d1a9e207 100644 --- a/docs/source/class/class_audio.rst +++ b/docs/source/class/class_audio.rst @@ -1,2 +1,4 @@ UAC ========================= + +参考官方 audio 相关 pdf \ No newline at end of file diff --git a/docs/source/class/class_cdc.rst b/docs/source/class/class_cdc.rst index 1ee9a86a..d3ed560f 100644 --- a/docs/source/class/class_cdc.rst +++ b/docs/source/class/class_cdc.rst @@ -1,2 +1,4 @@ CDC ========================= + +参考官方 cdc 相关 pdf \ No newline at end of file diff --git a/docs/source/class/class_hid.rst b/docs/source/class/class_hid.rst index 21b85cf2..0f9ef13d 100644 --- a/docs/source/class/class_hid.rst +++ b/docs/source/class/class_hid.rst @@ -1,2 +1,4 @@ HID ========================= + +参考官方 hid 相关 pdf \ No newline at end of file diff --git a/docs/source/class/class_msc.rst b/docs/source/class/class_msc.rst index ab230e70..c01a359c 100644 --- a/docs/source/class/class_msc.rst +++ b/docs/source/class/class_msc.rst @@ -1,2 +1,4 @@ MSC ========================= + +参考官方 msc 相关 pdf \ No newline at end of file diff --git a/docs/source/class/class_video.rst b/docs/source/class/class_video.rst index 7a1458ce..cabe5173 100644 --- a/docs/source/class/class_video.rst +++ b/docs/source/class/class_video.rst @@ -1,2 +1,4 @@ UVC ========================= + +参考官方 video 相关 pdf \ No newline at end of file diff --git a/docs/source/demo/audio_mic_speaker.rst b/docs/source/demo/audio_mic_speaker.rst new file mode 100644 index 00000000..3c1d2ca9 --- /dev/null +++ b/docs/source/demo/audio_mic_speaker.rst @@ -0,0 +1,43 @@ +USB 双通道麦克风和扬声器 +============================ + +软件实现 +------------ + +详细代码参考 `demo/audio_v1_mic_speaker_multichan_template.c` + +.. code-block:: C + + usbd_desc_register(audio_descriptor); + usbd_add_interface(usbd_audio_alloc_intf()); + usbd_add_interface(usbd_audio_alloc_intf()); + usbd_add_interface(usbd_audio_alloc_intf()); + usbd_add_endpoint(&audio_in_ep); + usbd_add_endpoint(&audio_out_ep); + + usbd_audio_add_entity(0x02, AUDIO_CONTROL_FEATURE_UNIT); + usbd_audio_add_entity(0x05, AUDIO_CONTROL_FEATURE_UNIT); + + usbd_initialize(); + +- 调用 `audio_init` 配置 audio 描述符并初始化 usb 硬件 +- 因为 麦克风+扬声器+控制需要 3 个接口,所以我们需要调用 `usbd_add_interface` 3 次 +- 默认描述符中开启了 mute 和 volume 的控制,所以需要注册对应的 entity,使用 `usbd_audio_add_entity` + +.. code-block:: C + + void usbd_audio_open(uint8_t intf) + { + } + void usbd_audio_close(uint8_t intf) + { + } + +- 当我们打开 PC 的音量图标,或者音乐播放器、麦克风界面时,会调用到这两个接口,用于启动或者停止数据传输 + +.. code-block:: C + + usbd_ep_start_write(AUDIO_IN_EP, write_buffer, 2048); + +- 由于 audio 协议中没有应用层相关的协议,传输的只有音频的原始数据,所以直接调用 `usbd_ep_start_write` 即可,发送完成会进入完成中断 +- 由于扬声器需要使用 out 端点,所以需要在 `usbd_configure_done_callback` 中启动第一次接收,当然如果没有能力接收,可以不启动,在想启动的时候启动 \ No newline at end of file diff --git a/docs/source/demo/cdc_acm.rst b/docs/source/demo/cdc_acm.rst new file mode 100644 index 00000000..3f6629d2 --- /dev/null +++ b/docs/source/demo/cdc_acm.rst @@ -0,0 +1,78 @@ +USB 虚拟串口(无 UART 功能) +============================ + +USB 虚拟串口主要是借助 USB CDC ACM 类实现,将其模拟成一个 VCP 设备,当插在电脑上的时候,可以显示成一个串口设备。跟市面上的 USB2TTL模块的区别在于,虚拟串口仅仅只使用到了 USB ,没有与串口(UART外设)进行连动。 + +软件实现 +------------ + +详细代码参考 `demo/cdc_acm_template.c` + +.. code-block:: C + + usbd_desc_register(cdc_descriptor); + usbd_add_interface(usbd_cdc_acm_alloc_intf()); + usbd_add_interface(usbd_cdc_acm_alloc_intf()); + usbd_add_endpoint(&cdc_out_ep); + usbd_add_endpoint(&cdc_in_ep); + usbd_initialize(); + +- 调用 `cdc_acm_init` 配置 cdc acm 描述符并初始化 usb 硬件 +- 因为 cdc 有 2 个接口,所以我们需要调用 `usbd_add_interface` 2 次 + +.. code-block:: C + + void usbd_configure_done_callback(void) + { + /* setup first out ep read transfer */ + usbd_ep_start_read(CDC_OUT_EP, read_buffer, 2048); + } + + void usbd_cdc_acm_bulk_out(uint8_t ep, uint32_t nbytes) + { + USB_LOG_RAW("actual out len:%d\r\n", nbytes); + // for (int i = 0; i < 100; i++) { + // printf("%02x ", read_buffer[i]); + // } + // printf("\r\n"); + /* setup next out ep read transfer */ + usbd_ep_start_read(CDC_OUT_EP, read_buffer, 2048); + } + + void usbd_cdc_acm_bulk_in(uint8_t ep, uint32_t nbytes) + { + USB_LOG_RAW("actual in len:%d\r\n", nbytes); + + if ((nbytes % CDC_MAX_MPS) == 0 && nbytes) { + /* send zlp */ + usbd_ep_start_write(CDC_IN_EP, NULL, 0); + } else { + ep_tx_busy_flag = false; + } + } + + void usbd_cdc_acm_set_dtr(uint8_t intf, bool dtr) + { + if (dtr) { + dtr_enable = 1; + } else { + dtr_enable = 0; + } + } + + void cdc_acm_data_send_with_dtr_test(void) + { + if (dtr_enable) { + memset(&write_buffer[10], 'a', 2038); + ep_tx_busy_flag = true; + usbd_ep_start_write(CDC_IN_EP, write_buffer, 2048); + while (ep_tx_busy_flag) { + } + } + } + +- `usbd_cdc_acm_set_dtr` 函数是主机发送流控命令时的回调函数,这里我们使用 dtr ,当开启 dtr 时,启动发送 +- `usbd_configure_done_callback` 是枚举完成的回调函数,因为 cdc acm 有 out 端点,所以我们需要在这里启动第一次数据的接收,当然,如果你现在没有能力接收数据,可以不启动。 **数据长度需要是最大包长的整数倍**。 +- `usbd_cdc_acm_bulk_out` 是接收完成中断回调,我们在这里面启动下一次接收 +- `usbd_cdc_acm_bulk_in` 是发送完成中断回调,我们在这里检查发送长度是否是最大包长的整数,如果是,需要发送 zlp 包表示结束 +- 调用 `usbd_ep_start_write` 进行发送,需要注意,如果返回值小于0,不能执行下面的 while \ No newline at end of file diff --git a/docs/source/demo/daplink.rst b/docs/source/demo/daplink.rst deleted file mode 100644 index 7fd292cb..00000000 --- a/docs/source/demo/daplink.rst +++ /dev/null @@ -1,2 +0,0 @@ -DAPLINK V2.0调试器 -========================= diff --git a/docs/source/demo/img/usb2uart1.png b/docs/source/demo/img/usb2uart1.png deleted file mode 100644 index 09822f15..00000000 Binary files a/docs/source/demo/img/usb2uart1.png and /dev/null differ diff --git a/docs/source/demo/mouse_keyboard.rst b/docs/source/demo/mouse_keyboard.rst deleted file mode 100644 index 11a1f22f..00000000 --- a/docs/source/demo/mouse_keyboard.rst +++ /dev/null @@ -1,2 +0,0 @@ -键盘与鼠标 -========================= diff --git a/docs/source/demo/msc_boot.rst b/docs/source/demo/msc_boot.rst deleted file mode 100644 index 6e15bfc3..00000000 --- a/docs/source/demo/msc_boot.rst +++ /dev/null @@ -1,2 +0,0 @@ -U盘制作 BootLoader -========================= diff --git a/docs/source/demo/msc_ram.rst b/docs/source/demo/msc_ram.rst new file mode 100644 index 00000000..3a97238d --- /dev/null +++ b/docs/source/demo/msc_ram.rst @@ -0,0 +1,42 @@ +USB 模拟 U 盘 +============================ + +软件实现 +------------ + +详细代码参考 `demo/msc_ram_template.c` + +.. code-block:: C + + usbd_desc_register(msc_ram_descriptor); + usbd_add_interface(usbd_msc_alloc_intf(MSC_OUT_EP, MSC_IN_EP)); + + usbd_initialize(); + +- 调用 `msc_ram_init` 配置 msc 描述符并初始化 usb 硬件 +- 因为 msc 有1个接口,所以我们需要调用 `usbd_add_interface` 1次 +- msc 中的端点的数据流是协议栈这边管理,所以不需要用户注册端点的回调函数。同理 `usbd_configure_done_callback` 也不需要,为空即可 + +.. code-block:: C + + void usbd_msc_get_cap(uint8_t lun, uint32_t *block_num, uint16_t *block_size) + { + *block_num = 1000; //Pretend having so many buffer,not has actually. + *block_size = BLOCK_SIZE; + } + int usbd_msc_sector_read(uint32_t sector, uint8_t *buffer, uint32_t length) + { + return 0; + } + + int usbd_msc_sector_write(uint32_t sector, uint8_t *buffer, uint32_t length) + { + return 0; + } + +- 实现三个接口即可使用 msc,读写操作如果没有 os 则是在中断中 +- `CONFIG_USBDEV_MSC_BLOCK_SIZE` 可以为 512 的整数倍,更改此项,可以增加 msc 的读写速度,当然,也会消耗更多的 ram + + +.. note:: MSC 一般配合 rtos 使用,因为读写操作是阻塞的,放中断是不合适的, `CONFIG_USBDEV_MSC_THREAD` 则是使能 os 管理 + diff --git a/docs/source/demo/speaker_mic.rst b/docs/source/demo/speaker_mic.rst deleted file mode 100644 index cb366ff0..00000000 --- a/docs/source/demo/speaker_mic.rst +++ /dev/null @@ -1,2 +0,0 @@ -USB 双通道扬声器和麦克风 -=========================== diff --git a/docs/source/demo/usb2uart.rst b/docs/source/demo/usb2uart.rst deleted file mode 100644 index b57b79b1..00000000 --- a/docs/source/demo/usb2uart.rst +++ /dev/null @@ -1,198 +0,0 @@ -USB 转串口 -========================= - -USB转串口即实现计算机USB接口到通用串口之间的转换。为没有串口的计算机提供快速的通道,而且,使用USB转串口设备等于将传统的串口设备变成了即插即用的USB设备。市面上的比如 CH340、FT232、PL2302 等等。 -所以如果需要实现该功能,那么我们使用的芯片需要具备以下两个条件: - -- 有 UART 外设 -- 有 USB DEVICE 外设 - -接下来,我们就可以愉快的进行代码的编写了。USB 转串口我们采用的是 CDC ACM 类。第一步我们先让 USB 能正常收发。 - -- 首先是实现 `usbd_cdc_acm_set_line_coding` 函数,这个函数的作用就是当我们点击电脑上的串口软件设置串口相关信息时(如下图所示),主机会通过 USB 发送设置串口的命令给设备,对设备上的串口进行配置,所以这边我们需要根据形参来配置串口。 - -.. figure:: img/usb2uart1.png - -- 其次实现 `usbd_cdc_acm_set_rts`,主要用来设置串口硬件流控。这里需要注意, windows 上任何软件是无法设置 RTS 的,可以说是 windows 驱动问题 -- 调用 `usbd_desc_register` 注册 cdc acm 描述符,包含设备描述符、配置描述符、cdc acm 特定描述符、接口描述符、端点描述符、字符串描述符等等 - -.. code-block:: C - - static const uint8_t cdc_descriptor[] = { - USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01), - USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER), - CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, 0x02), - /////////////////////////////////////// - /// 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 */ - 'C', 0x00, /* wcChar10 */ - 'D', 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 */ - '2', 0x00, /* wcChar3 */ - '1', 0x00, /* wcChar4 */ - '2', 0x00, /* wcChar5 */ - '3', 0x00, /* wcChar6 */ - '4', 0x00, /* wcChar7 */ - '5', 0x00, /* wcChar8 */ - '6', 0x00, /* wcChar9 */ - #ifdef CONFIG_USB_HS - /////////////////////////////////////// - /// device qualifier descriptor - /////////////////////////////////////// - 0x0a, - USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER, - 0x00, - 0x02, - 0x02, - 0x02, - 0x01, - 0x40, - 0x01, - 0x00, - #endif - 0x00 - }; - -.. caution:: 注意数组最后的结束符,不要遗漏 - -- cdc acm 一共需要两个接口,一个控制接口,一个数据接口,由于我们只有一个 cdc acm,所以只需要注册一个 class + 两个接口。其中控制接口需要一个中断端点,数据接口需要两个 bulk 端点,由于接口驱动我们已经支持,所以调用 cdc acm 相关的添加接口的 API 即可。代码如下: - -.. code-block:: C - - /*!< class */ - usbd_class_t cdc_class; - /*!< interface one */ - usbd_interface_t cdc_cmd_intf; - /*!< interface two */ - usbd_interface_t cdc_data_intf; - - /*!< endpoint call back */ - usbd_endpoint_t cdc_out_ep = { - .ep_addr = CDC_OUT_EP, - .ep_cb = usbd_cdc_acm_out - }; - - usbd_endpoint_t cdc_in_ep = { - .ep_addr = CDC_IN_EP, - .ep_cb = usbd_cdc_acm_in - }; - - usbd_desc_register(cdc_descriptor); - /*!< add interface */ - usbd_cdc_add_acm_interface(&cdc_class, &cdc_cmd_intf); - usbd_cdc_add_acm_interface(&cdc_class, &cdc_data_intf); - /*!< interface add endpoint */ - usbd_interface_add_endpoint(&cdc_data_intf, &cdc_out_ep); - usbd_interface_add_endpoint(&cdc_data_intf, &cdc_in_ep); - - usbd_initialize(); - -- 最后调用 `usbd_initialize` 初始化 usb。 - -.. code-block:: C - - /* function ------------------------------------------------------------------*/ - void usbd_cdc_acm_out(uint8_t ep) - { - uint8_t data[64]; - uint32_t read_byte; - - usbd_ep_read(ep, data, 64, &read_byte); - for (uint8_t i = 0; i < read_byte; i++) { - printf("%02x ", data[i]); - } - printf("\r\n"); - printf("read len:%d\r\n", read_byte); - usbd_ep_read(ep, NULL, 0, NULL); - } - - void usbd_cdc_acm_in(uint8_t ep) - { - printf("in\r\n"); - } - - volatile uint8_t dtr_enable = 0; - - void usbd_cdc_acm_set_dtr(bool dtr) - { - if (dtr) { - dtr_enable = 1; - } else { - dtr_enable = 0; - } - } - - void cdc_acm_data_send_with_dtr_test(void) - { - if (dtr_enable) { - uint8_t data_buffer[10] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x31, 0x32, 0x33, 0x34, 0x35 }; - usbd_ep_write(CDC_IN_EP, data_buffer, 10, NULL); - } - } - -- out 中断中我们将接收的数据进行打印,in 中断则是当 `usbd_ep_write` 发送完成后,进行打印 -- 实现 `usbd_cdc_acm_set_dtr` 进行流控 - -.. caution:: 注意端点接收中断中,接收 buf 的大小根据全速和高速来定,并且尽量不要在中断中开辟这么大的 buf - - -- 此时,插上电脑可以枚举出一个 USB 设备,名称为 **USB 串行设备(COMx)**,然后我们可以打开枚举的串口,发一些数据,然后看调试口是否有数据,有的话,证明 USB 方面是通的,那上面测试的一些代码就可以删删了。 - - -上面完成后,第二步,则是跟 UART 配合使用了,那怎么完成最终的 USB 转串口呢?首先我们需要梳理一下,整个的数据传输。 - -- 首先是 USB 发数据给设备,设备接收到数据以后,通过 UART TX 发送出去 -- 其次是 UART RX 接收的数据,通过 USB 发送给主机 - -所以关于 UART RX 我们可以使用中断接收,来接收数据,但是呢,UART RX 的数据如果太多,会丢,所以我们需要准备一个 Ringbuffer 组件,将 UART RX 接收的数据存到 Ringbuffer,同理, USB OUT 接收的数据也放到 Ringbuffer,所以我们需要准备两块 Ringbuffer。关于 Ringbuffer 原理和代码,大家自行百度。 -然后接下来的代码就非常简单啦,根据上面梳理的结果,代码呈现的结果就如下: - -- 初始化 Ringbuffer A 和 Ringbuffer B -- USB out 中断中读取数据并存入 Ringbuffer A 中 -- while(1) 中从 Ringbuffer A 中读取数据,并使用 UART 发送函数发出去 -- UART RX 中断中接收数据,并存入 Ringbuffer B 中,while(1)中从 Ringbuffer B 中读取数据,并使用 USB 发送函数发出去 - -代码参考 :https://github.com/bouffalolab/bl_mcu_sdk/tree/master/examples/usb/usb2uart \ No newline at end of file diff --git a/docs/source/demo/usb_video.rst b/docs/source/demo/usb_video.rst new file mode 100644 index 00000000..0e9b25ea --- /dev/null +++ b/docs/source/demo/usb_video.rst @@ -0,0 +1,2 @@ +USB 摄像头 +============================ diff --git a/docs/source/demo/video.rst b/docs/source/demo/video.rst deleted file mode 100644 index e89ec6f9..00000000 --- a/docs/source/demo/video.rst +++ /dev/null @@ -1,2 +0,0 @@ -USB 摄像头 -=========================== diff --git a/docs/source/index.rst b/docs/source/index.rst index 6abd8e22..208416e0 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -65,14 +65,12 @@ CherryUSB 是一个小而美的、可移植性高的、用于嵌入式系统的 .. toctree:: :maxdepth: 1 - :caption: 综合例程 + :caption: 基本例程 - demo/usb2uart - demo/mouse_keyboard - demo/msc_boot - demo/video - demo/speaker_mic - demo/daplink + demo/cdc_acm + demo/msc_ram + demo/audio_mic_speaker + demo/usb_video .. toctree:: :maxdepth: 1 diff --git a/docs/source/porting_usbip.rst b/docs/source/porting_usbip.rst index bf5ac711..0881c13e 100644 --- a/docs/source/porting_usbip.rst +++ b/docs/source/porting_usbip.rst @@ -1,4 +1,4 @@ -USB IP 差别说明 +USB IP 勘误 ============================== 本节主要对已经支持的 USB IP 在不同厂家上的一些差别说明并进行校对。欢迎补充。 diff --git a/docs/source/quick_start/stm32.rst b/docs/source/quick_start/stm32.rst index 754894b4..a5c3366a 100644 --- a/docs/source/quick_start/stm32.rst +++ b/docs/source/quick_start/stm32.rst @@ -86,6 +86,7 @@ USB Device 移植要点 .. figure:: img/stm32_9.png - 编译器推荐使用 **AC6**。勾选 **Microlib**,并实现 **printf** ,方便后续查看 log。 + .. figure:: img/stm32_10.png .. figure:: img/stm32_11.png @@ -109,6 +110,7 @@ USB Host 移植要点 .. figure:: img/stm32_16.png - 编译器推荐使用 **AC6**。勾选 **Microlib**,并实现 **printf** ,方便后续查看 log。 + .. figure:: img/stm32_10.png .. figure:: img/stm32_11.png diff --git a/docs/source/usb/usb2.0_basic.rst b/docs/source/usb/usb2.0_basic.rst index 92ba791d..4faa19dd 100644 --- a/docs/source/usb/usb2.0_basic.rst +++ b/docs/source/usb/usb2.0_basic.rst @@ -196,12 +196,14 @@ CRC 字段 .. figure:: img/24.png - 令牌CRC + 为令牌提供五位CRC字段,并覆盖IN,SETUP和OUT令牌的ADDR和ENDP字段或SOF令牌的时间戳字段。 PING和SPLIT特殊令牌还包括一个五位CRC字段。 生成多项式为: G(X)= X^5 + X^2 + 1 表示该多项式的二进制位模式是00101B。 如果接收到所有令牌位而没有错误,则接收器处的五位校验和将为01100B。 - 数据CRC + 数据CRC是应用于数据分组的数据字段的16位多项式。 生成多项式是:G(X)= X^16 + X^15 + X^2 + 1 @@ -260,6 +262,8 @@ SOF 包的字段组成,如图: USB 事务 --------------------- +USB 常用事务共有三种:SETUP、IN、OUT,除了控制传输使用三个事务,其他传输都使用两个事务。特殊事务则是不携带数据的事务。 + SETUP 事务 ^^^^^^^^^^^^^^^^^^^^^^^^