Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
859db28964 | ||
|
|
6b0ec0e16f | ||
|
|
1a5bc9d150 | ||
|
|
08d1ce4ab5 | ||
|
|
0cac0ab34c | ||
|
|
5f47d1a6b6 | ||
|
|
64dced8ec7 | ||
|
|
eaefb8ed21 |
2
.github/workflows/deploy-docs.yml
vendored
@@ -23,6 +23,6 @@ jobs:
|
||||
- uses: JamesIves/github-pages-deploy-action@v4
|
||||
with:
|
||||
branch: gh-pages
|
||||
folder: docs/build/html
|
||||
folder: docs/output/zh/html
|
||||
|
||||
|
||||
|
||||
13
Kconfig
@@ -138,6 +138,11 @@ if CHERRYUSB
|
||||
prompt "Enable usb dfu device"
|
||||
default n
|
||||
|
||||
config CHERRYUSB_DEVICE_DISPLAY
|
||||
bool
|
||||
prompt "Enable usb display device"
|
||||
default n
|
||||
|
||||
config USBDEV_REQUEST_BUFFER_LEN
|
||||
int
|
||||
prompt "Set device control transfer max buffer size"
|
||||
@@ -211,6 +216,10 @@ if CHERRYUSB
|
||||
bool
|
||||
prompt "cdc_ncm"
|
||||
depends on CHERRYUSB_DEVICE_CDC_NCM
|
||||
config CHERRYUSB_DEVICE_TEMPLATE_DFU
|
||||
bool
|
||||
prompt "dfu"
|
||||
depends on CHERRYUSB_DEVICE_DFU
|
||||
config CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC
|
||||
bool
|
||||
prompt "cdc_acm_msc"
|
||||
@@ -233,6 +242,10 @@ if CHERRYUSB
|
||||
bool
|
||||
prompt "webusb_hid"
|
||||
depends on CHERRYUSB_DEVICE_HID
|
||||
config CHERRYUSB_DEVICE_TEMPLATE_DISPLAY
|
||||
bool
|
||||
prompt "display"
|
||||
depends on CHERRYUSB_DEVICE_DISPLAY
|
||||
endchoice
|
||||
endif
|
||||
|
||||
|
||||
13
Kconfig.rtt
@@ -139,6 +139,11 @@ if RT_USING_CHERRYUSB
|
||||
prompt "Enable usb dfu device"
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_DEVICE_DISPLAY
|
||||
bool
|
||||
prompt "Enable usb display device"
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_DEVICE_CDC_ACM_CHARDEV
|
||||
bool
|
||||
prompt "Enable chardev for cdc acm device"
|
||||
@@ -221,6 +226,10 @@ if RT_USING_CHERRYUSB
|
||||
bool
|
||||
prompt "cdc_ncm"
|
||||
depends on RT_CHERRYUSB_DEVICE_CDC_NCM
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_DFU
|
||||
bool
|
||||
prompt "dfu"
|
||||
depends on RT_CHERRYUSB_DEVICE_DFU
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC
|
||||
bool
|
||||
prompt "cdc_acm_msc"
|
||||
@@ -243,6 +252,10 @@ if RT_USING_CHERRYUSB
|
||||
bool
|
||||
prompt "webusb_hid"
|
||||
depends on RT_CHERRYUSB_DEVICE_HID
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_DISPLAY
|
||||
bool
|
||||
prompt "display"
|
||||
depends on RT_CHERRYUSB_DEVICE_DISPLAY
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_ADB
|
||||
bool
|
||||
prompt "adb"
|
||||
|
||||
@@ -138,6 +138,11 @@ if PKG_USING_CHERRYUSB
|
||||
prompt "Enable usb dfu device"
|
||||
default n
|
||||
|
||||
config PKG_CHERRYUSB_DEVICE_DISPLAY
|
||||
bool
|
||||
prompt "Enable usb display device"
|
||||
default n
|
||||
|
||||
config PKG_CHERRYUSB_DEVICE_CDC_ACM_CHARDEV
|
||||
bool
|
||||
prompt "Enable chardev for cdc acm device"
|
||||
@@ -220,6 +225,10 @@ if PKG_USING_CHERRYUSB
|
||||
bool
|
||||
prompt "cdc_ncm"
|
||||
depends on PKG_CHERRYUSB_DEVICE_CDC_NCM
|
||||
config PKG_CHERRYUSB_DEVICE_TEMPLATE_DFU
|
||||
bool
|
||||
prompt "dfu"
|
||||
depends on PKG_CHERRYUSB_DEVICE_DFU
|
||||
config PKG_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC
|
||||
bool
|
||||
prompt "cdc_acm_msc"
|
||||
@@ -242,6 +251,10 @@ if PKG_USING_CHERRYUSB
|
||||
bool
|
||||
prompt "webusb_hid"
|
||||
depends on PKG_CHERRYUSB_DEVICE_HID
|
||||
config PKG_CHERRYUSB_DEVICE_TEMPLATE_DISPLAY
|
||||
bool
|
||||
prompt "display"
|
||||
depends on PKG_CHERRYUSB_DEVICE_DISPLAY
|
||||
config PKG_CHERRYUSB_DEVICE_TEMPLATE_ADB
|
||||
bool
|
||||
prompt "adb"
|
||||
|
||||
88
README.md
@@ -14,31 +14,31 @@ CherryUSB is a tiny and beautiful, high performance and portable USB host and de
|
||||
|
||||
## Why choose CherryUSB
|
||||
|
||||
### Easy to study USB
|
||||
### Easy to Learn USB
|
||||
|
||||
In order to make it easier for users to learn USB basics, enumeration, driver loading and IP drivers, the code has been written with the following advantages:
|
||||
To facilitate user learning of USB fundamentals, enumeration, driver loading, and IP drivers, the written code has the following advantages:
|
||||
|
||||
- Lean code, simple logic, no complex C syntax
|
||||
- Tree-based programming with cascading code
|
||||
- Class-drivers and porting-drivers are templating and simplification
|
||||
- Clear API classification (slave: initialisation, registration api, command callback api, data sending and receiving api; host: initialisation, lookup api, data sending and receiving api)
|
||||
- Streamlined code with simple logic and no complex C language syntax
|
||||
- Tree-structured programming with progressive code layers
|
||||
- Templated and simplified Class drivers and porting drivers
|
||||
- Clear API categorization (Device: initialization, class registration, command callbacks, data transmission; Host: initialization, class discovery, data transmission)
|
||||
|
||||
### Easy to use USB
|
||||
### Easy to Use USB
|
||||
|
||||
In order to facilitate the use of the USB interface and to take into account the fact that users have learned about uart and dma, the following advantages have been designed for the data sending and receiving class of interface:
|
||||
To facilitate user interaction with USB interfaces, considering users’ familiarity with UART and DMA, the designed data transmission interface has the following advantages:
|
||||
|
||||
- Equivalent to using uart tx dma/uart rx dma
|
||||
- There is no limit to the length of send and receive, the user does not need to care about the USB packetization process (the porting driver does it)
|
||||
- Equivalent to using UART TX DMA/UART RX DMA
|
||||
- No length restrictions on transmission/reception; users don’t need to worry about USB packetization (porting drivers handle packetization)
|
||||
|
||||
### Easy to bring out USB performance
|
||||
### Easy to Achieve USB Performance
|
||||
|
||||
Taking into account USB performance issues and trying to achieve the theoretical bandwidth of the USB hardware, the design of the data transceiver class interface has the following advantages:
|
||||
Considering USB performance requirements to reach theoretical USB hardware bandwidth, the designed data transmission interface has the following advantages:
|
||||
|
||||
- Porting drivers directly to registers, no abstraction layer encapsulation
|
||||
- Porting drivers directly interface with registers without abstraction layer encapsulation
|
||||
- Memory zero copy
|
||||
- If IP has DMA then uses DMA mode (DMA with hardware packetization)
|
||||
- Unlimited length make it easier to interface with hardware DMA and take advantage of DMA
|
||||
- Packetization is handled in interrupt
|
||||
- DMA mode used when IP supports DMA (DMA provides hardware packetization functionality)
|
||||
- No length restrictions, facilitating hardware DMA interfacing and maximizing DMA advantages
|
||||
- Packetization handled in interrupt context
|
||||
|
||||
Performance show:https://cherryusb.cherry-embedded.org/show/
|
||||
|
||||
@@ -75,6 +75,7 @@ CherryUSB Device Stack has the following functions:
|
||||
- Support Remote NDIS (RNDIS)
|
||||
- Support Media Transfer Protocol (MTP)
|
||||
- Support WINUSB1.0, WINUSB2.0, WEBUSB, BOS
|
||||
- Support Vendor display ([xfz1986_usb_graphic_driver](https://github.com/chuanjinpang/win10_idd_xfz1986_usb_graphic_driver_display))
|
||||
- Support Vendor class
|
||||
- Support UF2
|
||||
- Support Android Debug Bridge (Only support shell)
|
||||
@@ -93,6 +94,7 @@ CherryUSB Device Stack resource usage (GCC 10.2 with -O2, disable log):
|
||||
|usbd_rndis.c | ~2500 | 2 * 1580(default)+156+8 | 80 | 0 |
|
||||
|usbd_cdc_ecm.c | ~900 | 2 * 1514(default)+16 | 42 | 0 |
|
||||
|usbd_mtp.c | ~9000 | 2048(default)+128 | sizeof(struct mtp_object) * n| 0 |
|
||||
|usbd_dfu.c | ~2200 | 0 | 45 | 0 |
|
||||
|
||||
## Host Stack Overview
|
||||
|
||||
@@ -176,55 +178,31 @@ Only standard and commercial USB IP are listed.
|
||||
| CDNS3(cadence) | CDNS3 | XHCI | × |
|
||||
| DWC3(synopsys) | DWC3 | XHCI | × |
|
||||
|
||||
## Documentation Tutorial
|
||||
## Resources
|
||||
|
||||
Quickly start, USB basic concepts, API manual, Class basic concepts and examples, see [CherryUSB Documentation Tutorial](https://cherryusb.readthedocs.io/).
|
||||
### Getting Started
|
||||
|
||||
## Video Tutorial
|
||||
- 📖 [CherryUSB Documentation](https://cherryusb.readthedocs.io/en/latest/)
|
||||
- 💻 [CherryUSB Demo Repo](https://cherryusb.readthedocs.io/en/latest/quick_start/demo.html)
|
||||
- 📺 [CherryUSB Cheese(>= V1.4.3)](https://www.bilibili.com/cheese/play/ss707687201)
|
||||
|
||||
CherryUSB Cheese (>= V1.4.3): https://www.bilibili.com/cheese/play/ss707687201 .
|
||||
|
||||
## Descriptor Generator Tool
|
||||
|
||||
Cherry Descriptor: https://desc.cherry-embedded.org/en
|
||||
|
||||
## Demo Repo
|
||||
|
||||
| Manufacturer | CHIP or Series | USB IP| Repo Url | Support version | Note |
|
||||
|:--------------------:|:------------------:|:-----:|:--------:|:------------------:|:-------------:|
|
||||
|Bouffalolab | BL702/BL616/BL808 | bouffalolab/ehci|[bouffalo_sdk](https://github.com/CherryUSB/bouffalo_sdk)|<= latest | Official |
|
||||
|ST | STM32F1x/STM32F4/STM32H7 | fsdev/dwc2 |[stm32_repo](https://github.com/CherryUSB/cherryusb_stm32)|<= latest | Community |
|
||||
|HPMicro | HPM6000/HPM5000 | hpm/ehci |[hpm_sdk](https://github.com/CherryUSB/hpm_sdk)|<= latest | Official |
|
||||
|Essemi | ES32F36xx | musb |[es32f369_repo](https://github.com/CherryUSB/cherryusb_es32)|<= latest | Official |
|
||||
|Phytium | e2000 | pusb2/xhci |[phytium_repo](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk)|>=1.4.0 | Official |
|
||||
|Artinchip | d12x/d13x/d21x | aic/ehci/ohci |[luban-lite](https://gitee.com/artinchip/luban-lite)|<= latest | Official |
|
||||
|Espressif | esp32s2/esp32s3/esp32p4 | dwc2 |[esp32_repo](https://github.com/CherryUSB/cherryusb_esp32)/[espressif](https://github.com/espressif/esp-idf/tree/master/examples/peripherals/usb)|<= latest | Official |
|
||||
|Kendryte | k230 | dwc2 |[k230_repo](https://github.com/CherryUSB/k230_sdk)|v1.2.0 | Official |
|
||||
|Actionstech | ATS30xx | dwc2 |[action_zephyr_repo](https://github.com/CherryUSB/lv_port_actions_technology/tree/master/action_technology_sdk)|>=1.4.0 | Official |
|
||||
|SiFli | SF32LB5x | musb |[SiFli_sdk](https://github.com/OpenSiFli/SiFli-SDK)|>=1.5.0 | Official |
|
||||
|NXP | mcx | kinetis/chipidea/ehci |[nxp_mcx_repo](https://github.com/CherryUSB/cherryusb_mcx)|<= latest | Community |
|
||||
|Nationstech | n32h4x | dwc2 |[nation_repo](https://github.com/CherryUSB/cherryusb_nation)|>=1.5.0 | Official ongoing |
|
||||
|Raspberry pi | rp2040/rp2350 | rp2040 |[pico-sdk](https://github.com/CherryUSB/pico-sdk)|<= latest | Official ongoing |
|
||||
|AllwinnerTech | F1C100S/F1C200S | musb |[cherryusb_rtt_f1c100s](https://github.com/CherryUSB/cherryusb_rtt_f1c100s)|<= latest | no more update |
|
||||
|Bekencorp | bk7256/bk7258 | musb |[bk_idk](https://github.com/CherryUSB/bk_idk)| v0.7.0 | Official |
|
||||
|Sophgo | cv18xx | dwc2 |[cvi_alios_open](https://github.com/CherryUSB/cvi_alios_open)| v0.7.0 | Official |
|
||||
|WCH | CH32V307/ch58x | ch32_usbfs/ch32_usbhs/ch58x |[wch_repo](https://github.com/CherryUSB/cherryusb_wch)|<= v0.10.2/>=v1.5.0 | no more update |
|
||||
|
||||
## Package Support
|
||||
|
||||
CherryUSB package is available as follows:
|
||||
### Package Support
|
||||
|
||||
- [RT-Thread](https://packages.rt-thread.org/detail.html?package=CherryUSB)
|
||||
- [YOC](https://www.xrvm.cn/document?temp=usb-host-protocol-stack-device-driver-adaptation-instructions&slug=yocbook)
|
||||
- [ESP-Registry](https://components.espressif.com/components/cherry-embedded/cherryusb)
|
||||
|
||||
### Descriptor Generator Tool
|
||||
|
||||
Cherry Descriptor: https://desc.cherry-embedded.org/en
|
||||
|
||||
### Contact
|
||||
|
||||
CherryUSB discord: https://discord.com/invite/wFfvrSAey8
|
||||
|
||||
## Commercial Support
|
||||
|
||||
Refer to https://cherryusb.readthedocs.io/zh-cn/latest/support/index.html.
|
||||
|
||||
## Contact
|
||||
|
||||
CherryUSB discord: https://discord.com/invite/wFfvrSAey8.
|
||||
Refer to https://cherryusb.readthedocs.io/en/latest/support/index.html
|
||||
|
||||
## Company Support
|
||||
|
||||
|
||||
52
README_zh.md
@@ -75,6 +75,7 @@ CherryUSB Device 协议栈当前实现以下功能:
|
||||
- 支持 Remote NDIS (RNDIS)
|
||||
- 支持 Media Transfer Protocol (MTP)
|
||||
- 支持 WINUSB1.0、WINUSB2.0、WEBUSB、BOS
|
||||
- 支持 Vendor display ([xfz1986_usb_graphic_driver](https://github.com/chuanjinpang/win10_idd_xfz1986_usb_graphic_driver_display))
|
||||
- 支持 Vendor 类 class
|
||||
- 支持 UF2
|
||||
- 支持 Android Debug Bridge (Only support shell)
|
||||
@@ -93,6 +94,7 @@ CherryUSB Device 协议栈资源占用说明(GCC 10.2 with -O2):
|
||||
|usbd_rndis.c | ~2500 | 2 * 1580(default)+156+8 | 80 | 0 |
|
||||
|usbd_cdc_ecm.c | ~900 | 2 * 1514(default)+16 | 42 | 0 |
|
||||
|usbd_mtp.c | ~9000 | 2048(default)+128 | sizeof(struct mtp_object) * n| 0 |
|
||||
|usbd_dfu.c | ~2200 | 0 | 45 | 0 |
|
||||
|
||||
## Host 协议栈简介
|
||||
|
||||
@@ -176,58 +178,34 @@ x 受以下宏影响:
|
||||
| CDNS3(cadence) | CDNS3 | XHCI | × |
|
||||
| DWC3(synopsys) | DWC3 | XHCI | × |
|
||||
|
||||
## 文档教程
|
||||
## Resources
|
||||
|
||||
CherryUSB 快速入门、USB 基本概念、API 手册、Class 基本概念和例程,参考 [CherryUSB Documentation Tutorial](https://cherryusb.readthedocs.io/)。
|
||||
### 快速开始
|
||||
|
||||
## 视频教程
|
||||
- 📖 [CherryUSB Documentation](https://cherryusb.readthedocs.io/zh-cn/latest/)
|
||||
- 💻 [CherryUSB Demo Repo](https://cherryusb.readthedocs.io/zh-cn/latest/quick_start/demo.html)
|
||||
- 📺 [CherryUSB Cheese(>= V1.4.3)](https://www.bilibili.com/cheese/play/ss707687201)
|
||||
|
||||
CherryUSB 课程(>= V1.4.3):https://www.bilibili.com/cheese/play/ss707687201 。
|
||||
|
||||
## 描述符生成工具
|
||||
|
||||
Cherry Descriptor: https://desc.cherry-embedded.org/zh
|
||||
|
||||
## 示例仓库
|
||||
|
||||
| Manufacturer | CHIP or Series | USB IP| Repo Url | Support version | Note |
|
||||
|:--------------------:|:------------------:|:-----:|:--------:|:------------------:|:-------------:|
|
||||
|Bouffalolab | BL702/BL616/BL808 | bouffalolab/ehci|[bouffalo_sdk](https://github.com/CherryUSB/bouffalo_sdk)|<= latest | Official |
|
||||
|ST | STM32F1x/STM32F4/STM32H7 | fsdev/dwc2 |[stm32_repo](https://github.com/CherryUSB/cherryusb_stm32)|<= latest | Community |
|
||||
|HPMicro | HPM6000/HPM5000 | hpm/ehci |[hpm_sdk](https://github.com/CherryUSB/hpm_sdk)|<= latest | Official |
|
||||
|Essemi | ES32F36xx | musb |[es32f369_repo](https://github.com/CherryUSB/cherryusb_es32)|<= latest | Official |
|
||||
|Phytium | e2000 | pusb2/xhci |[phytium_repo](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk)|>=1.4.0 | Official |
|
||||
|Artinchip | d12x/d13x/d21x | aic/ehci/ohci |[luban-lite](https://gitee.com/artinchip/luban-lite)|<= latest | Official |
|
||||
|Espressif | esp32s2/esp32s3/esp32p4 | dwc2 |[esp32_repo](https://github.com/CherryUSB/cherryusb_esp32)/[espressif](https://github.com/espressif/esp-idf/tree/master/examples/peripherals/usb)|<= latest | Official |
|
||||
|Kendryte | k230 | dwc2 |[k230_repo](https://github.com/CherryUSB/k230_sdk)|v1.2.0 | Official |
|
||||
|Actionstech | ATS30xx | dwc2 |[action_zephyr_repo](https://github.com/CherryUSB/lv_port_actions_technology/tree/master/action_technology_sdk)|>=1.4.0 | Official |
|
||||
|SiFli | SF32LB5x | musb |[SiFli_sdk](https://github.com/OpenSiFli/SiFli-SDK)|>=1.5.0 | Official |
|
||||
|NXP | mcx | kinetis/chipidea/ehci |[nxp_mcx_repo](https://github.com/CherryUSB/cherryusb_mcx)|<= latest | Community |
|
||||
|Nationstech | n32h4x | dwc2 |[nation_repo](https://github.com/CherryUSB/cherryusb_nation)|>=1.5.0 | Official ongoing |
|
||||
|Raspberry pi | rp2040/rp2350 | rp2040 |[pico-sdk](https://github.com/CherryUSB/pico-sdk)|<= latest | Official ongoing |
|
||||
|AllwinnerTech | F1C100S/F1C200S | musb |[cherryusb_rtt_f1c100s](https://github.com/CherryUSB/cherryusb_rtt_f1c100s)|<= latest | no more update |
|
||||
|Bekencorp | bk7256/bk7258 | musb |[bk_idk](https://github.com/CherryUSB/bk_idk)| v0.7.0 | Official |
|
||||
|Sophgo | cv18xx | dwc2 |[cvi_alios_open](https://github.com/CherryUSB/cvi_alios_open)| v0.7.0 | Official |
|
||||
|WCH | CH32V307/ch58x | ch32_usbfs/ch32_usbhs/ch58x |[wch_repo](https://github.com/CherryUSB/cherryusb_wch)|<= v0.10.2/>=v1.5.0 | no more update |
|
||||
|
||||
## 软件包支持
|
||||
|
||||
CherryUSB 软件包可以通过以下方式获取:
|
||||
### 软件包支持
|
||||
|
||||
- [RT-Thread](https://packages.rt-thread.org/detail.html?package=CherryUSB)
|
||||
- [YOC](https://www.xrvm.cn/document?temp=usb-host-protocol-stack-device-driver-adaptation-instructions&slug=yocbook)
|
||||
- [ESP-Registry](https://components.espressif.com/components/cherry-embedded/cherryusb)
|
||||
|
||||
## 商业支持
|
||||
### 描述符生成工具
|
||||
|
||||
参考 https://cherryusb.readthedocs.io/zh-cn/latest/support/index.html 。
|
||||
Cherry Descriptor: https://desc.cherry-embedded.org/zh
|
||||
|
||||
## 联系
|
||||
### Contact
|
||||
|
||||
CherryUSB QQ群:642693751
|
||||
|
||||
CherryUSB 微信群:与我联系后邀请加入
|
||||
|
||||
## 商业支持
|
||||
|
||||
参考 https://cherryusb.readthedocs.io/zh-cn/latest/support/index.html
|
||||
|
||||
## 支持企业
|
||||
|
||||
感谢以下企业支持(顺序不分先后):
|
||||
|
||||
10
SConscript
@@ -17,6 +17,7 @@ path += [cwd + '/class/dfu']
|
||||
path += [cwd + '/class/serial']
|
||||
path += [cwd + '/class/vendor/net']
|
||||
path += [cwd + '/class/vendor/wifi']
|
||||
path += [cwd + '/class/vendor/display']
|
||||
src = []
|
||||
|
||||
LIBS = []
|
||||
@@ -136,6 +137,11 @@ if GetDepend(['PKG_CHERRYUSB_DEVICE']):
|
||||
src += Glob('class/cdc/usbd_cdc_ncm.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_DFU']):
|
||||
src += Glob('class/dfu/usbd_dfu.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_DISPLAY']):
|
||||
src += Glob('class/vendor/display/usbd_display.c')
|
||||
src += Glob('third_party/cherrymp/chry_mempool.c')
|
||||
src += Glob('third_party/cherrymp/chry_mempool_osal_rtthread.c')
|
||||
path += [cwd + '/third_party/cherrymp']
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_ADB']):
|
||||
src += Glob('class/adb/usbd_adb.c')
|
||||
src += Glob('platform/rtthread/usbd_adb_shell.c')
|
||||
@@ -165,6 +171,8 @@ if GetDepend(['PKG_CHERRYUSB_DEVICE']):
|
||||
src += Glob('demo/cdc_ecm_template.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_CDC_NCM']):
|
||||
src += Glob('demo/cdc_ncm_template.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_DFU']):
|
||||
src += Glob('demo/dfu_template.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC']):
|
||||
src += Glob('demo/cdc_acm_msc_template.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC_HID']):
|
||||
@@ -177,6 +185,8 @@ if GetDepend(['PKG_CHERRYUSB_DEVICE']):
|
||||
src += Glob('demo/winusb2.0_cdc_template.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_WEBUSB_HID']):
|
||||
src += Glob('demo/webusb_hid_template.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_DISPLAY']):
|
||||
src += Glob('demo/display/usbdisplay_template.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_ADB']):
|
||||
src += Glob('demo/adb/usbd_adb_template.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_CHARDEV']):
|
||||
|
||||
@@ -50,6 +50,7 @@ list(
|
||||
${CMAKE_CURRENT_LIST_DIR}/class/serial
|
||||
${CMAKE_CURRENT_LIST_DIR}/class/vendor/net
|
||||
${CMAKE_CURRENT_LIST_DIR}/class/vendor/wifi
|
||||
${CMAKE_CURRENT_LIST_DIR}/class/vendor/display
|
||||
${CMAKE_CURRENT_LIST_DIR}/class/aoa
|
||||
${CMAKE_CURRENT_LIST_DIR}/class/gamepad
|
||||
)
|
||||
@@ -89,6 +90,9 @@ if(CONFIG_CHERRYUSB_DEVICE)
|
||||
if(CONFIG_CHERRYUSB_DEVICE_GAMEPAD)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/gamepad/usbd_gamepad.c)
|
||||
endif()
|
||||
if(CONFIG_CHERRYUSB_DEVICE_DISPLAY)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/vendor/display/usbd_display.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_CHERRYUSB_DEVICE_FSDEV_ST)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/fsdev/usb_dc_fsdev.c)
|
||||
|
||||
@@ -49,7 +49,6 @@ static int audio_class_endpoint_request_handler(uint8_t busid, struct usb_setup_
|
||||
|
||||
break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Audio Class control selector 0x%02x\r\n", control_selector);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -109,7 +108,6 @@ static int audio_class_interface_request_handler(uint8_t busid, struct usb_setup
|
||||
*len = 1;
|
||||
break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x in cs 0x%02x\r\n", setup->bRequest, control_selector);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
@@ -124,7 +122,6 @@ static int audio_class_interface_request_handler(uint8_t busid, struct usb_setup
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x in cs 0x%02x\r\n", setup->bRequest, control_selector);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -169,7 +166,6 @@ static int audio_class_interface_request_handler(uint8_t busid, struct usb_setup
|
||||
*len = 2;
|
||||
break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x in cs 0x%02x\r\n", setup->bRequest, control_selector);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
@@ -207,14 +203,12 @@ static int audio_class_interface_request_handler(uint8_t busid, struct usb_setup
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x in cs 0x%02x\r\n", setup->bRequest, control_selector);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Audio Class cs 0x%02x \r\n", control_selector);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -247,7 +241,6 @@ static int audio_class_interface_request_handler(uint8_t busid, struct usb_setup
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x in cs 0x%02x\r\n", setup->bRequest, control_selector);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -261,7 +254,6 @@ static int audio_class_interface_request_handler(uint8_t busid, struct usb_setup
|
||||
break;
|
||||
|
||||
default:
|
||||
//USB_LOG_WRN("Unhandled Audio Class cs 0x%02x \r\n", control_selector);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -76,7 +76,6 @@ static int cdc_acm_class_interface_request_handler(uint8_t busid, struct usb_set
|
||||
usbd_cdc_acm_send_break(busid, intf_num);
|
||||
break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled CDC Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -106,7 +106,6 @@ static int cdc_ecm_class_interface_request_handler(uint8_t busid, struct usb_set
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled CDC ECM Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#define DFU_PROTOCOL_RUNTIME 0x01
|
||||
|
||||
/** DFU Class DFU mode Protocol */
|
||||
#define DFU_PROTOCOL_MODE 0x02
|
||||
#define DFU_PROTOCOL_DFU 0x02
|
||||
|
||||
/**
|
||||
* @brief DFU Class Specific Requests
|
||||
@@ -76,21 +76,23 @@
|
||||
#define DFU_STATE_DFU_UPLOAD_IDLE 9U
|
||||
#define DFU_STATE_DFU_ERROR 10U
|
||||
|
||||
/** DFU Manifestation State */
|
||||
#define DFU_MANIFEST_COMPLETE 0U
|
||||
#define DFU_MANIFEST_IN_PROGRESS 1U
|
||||
/* Define DFU application notification signals. */
|
||||
#define DFU_NOTIFICATION_BEGIN_DOWNLOAD 0x1u
|
||||
#define DFU_NOTIFICATION_END_DOWNLOAD 0x2u
|
||||
#define DFU_NOTIFICATION_ABORT_DOWNLOAD 0x3u
|
||||
#define DFU_NOTIFICATION_BEGIN_UPLOAD 0x5u
|
||||
#define DFU_NOTIFICATION_END_UPLOAD 0x6u
|
||||
#define DFU_NOTIFICATION_ABORT_UPLOAD 0x7u
|
||||
|
||||
/** Special Commands with Download Request */
|
||||
#define DFU_CMD_GETCOMMANDS 0U
|
||||
#define DFU_CMD_SETADDRESSPOINTER 0x21U
|
||||
#define DFU_CMD_ERASE 0x41U
|
||||
#define DFU_MEDIA_ERASE 0x00U
|
||||
#define DFU_MEDIA_PROGRAM 0x01U
|
||||
/* Define DFU application notification signals. */
|
||||
#define DFU_MEDIA_STATUS_OK 0
|
||||
#define DFU_MEDIA_STATUS_BUSY 1
|
||||
#define DFU_MEDIA_STATUS_ERROR 2
|
||||
|
||||
/** Other defines */
|
||||
/* Bit Detach capable = bit 3 in bmAttributes field */
|
||||
#define DFU_DETACH_MASK (1U << 3)
|
||||
#define DFU_MANIFEST_MASK (1U << 2)
|
||||
/** Special Commands with Download Request for STM32, wValue = 0 */
|
||||
#define DFU_SPECIAL_CMD_SET_ADDRESS_POINTER 0x21U
|
||||
#define DFU_SPECIAL_CMD_ERASE 0x41U
|
||||
#define DFU_SPECIAL_READ_UNPROTECT 0x92U
|
||||
|
||||
/** Run-Time Functional Descriptor */
|
||||
struct dfu_runtime_descriptor {
|
||||
@@ -103,35 +105,36 @@ struct dfu_runtime_descriptor {
|
||||
} __PACKED;
|
||||
|
||||
/**\brief Payload packet to response in DFU_GETSTATUS request */
|
||||
struct dfu_info {
|
||||
struct dfu_status {
|
||||
uint8_t bStatus; /**<\brief An indication of the status resulting from the
|
||||
* execution of the most recent request.*/
|
||||
uint8_t bPollTimeout; /**<\brief Minimum time (LSB) in ms, that the host should wait
|
||||
* before sending a subsequent DFU_GETSTATUS request.*/
|
||||
uint16_t wPollTimeout; /**<\brief Minimum time (MSB) in ms, that the host should wait
|
||||
uint32_t bwPollTimeout; /**<\brief Minimum time in ms, that the host should wait
|
||||
* before sending a subsequent DFU_GETSTATUS request.*/
|
||||
uint8_t bState; /**<\brief An indication of the state that the device is going
|
||||
* to enter immediately following transmission of this response.*/
|
||||
uint8_t iString; /**<\brief Index of the status string descriptor.*/
|
||||
};
|
||||
|
||||
#define DFU_DESCRIPTOR_LEN 18
|
||||
|
||||
// clang-format off
|
||||
#define DFU_DESCRIPTOR_INIT() \
|
||||
#define DFU_DESCRIPTOR_INIT(str_idx) \
|
||||
0x09, /* bLength */ \
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
|
||||
0x00, /* bInterfaceNumber */ \
|
||||
0x00, /* bAlternateSetting */ \
|
||||
0x00, /* bNumEndpoints Default Control Pipe only */ \
|
||||
USB_DEVICE_CLASS_APP_SPECIFIC, /* bInterfaceClass */ \
|
||||
0x01, /* bInterfaceSubClass Device Firmware Upgrade */ \
|
||||
0x02, /* bInterfaceProtocol DFU mode */ \
|
||||
0x04, /* iInterface */ /*!< Device Firmware Update Functional Descriptor */ \
|
||||
DFU_SUBCLASS_DFU, /* bInterfaceSubClass Device Firmware Upgrade */ \
|
||||
DFU_PROTOCOL_DFU, /* bInterfaceProtocol DFU mode */ \
|
||||
str_idx, /* iInterface */ \
|
||||
/*!< Device Firmware Update Functional Descriptor */ \
|
||||
0x09, /* bLength */ \
|
||||
0x21, /* DFU Functional Descriptor */ \
|
||||
0x0B, /* bmAttributes */ \
|
||||
WBVAL(0x00ff), /* wDetachTimeOut */ \
|
||||
WBVAL(USBD_DFU_XFER_SIZE), /* wTransferSize */ \
|
||||
WBVAL(0x011a) /* bcdDFUVersion */
|
||||
WBVAL(CONFIG_USBDEV_REQUEST_BUFFER_LEN), /* wTransferSize */ \
|
||||
WBVAL(DFU_VERSION) /* bcdDFUVersion */
|
||||
// clang-format on
|
||||
|
||||
#endif /* USB_DFU_H */
|
||||
|
||||
@@ -1,431 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2022, sakumisu
|
||||
* Copyright (c) 2022 ~ 2026, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbd_core.h"
|
||||
#include "usbd_dfu.h"
|
||||
|
||||
/** Modify the following three parameters according to different platforms */
|
||||
#ifndef USBD_DFU_XFER_SIZE
|
||||
#define USBD_DFU_XFER_SIZE 1024
|
||||
#endif
|
||||
|
||||
#ifndef USBD_DFU_APP_DEFAULT_ADD
|
||||
#define USBD_DFU_APP_DEFAULT_ADD 0x8004000
|
||||
#endif
|
||||
|
||||
#ifndef FLASH_PROGRAM_TIME
|
||||
#define FLASH_PROGRAM_TIME 50
|
||||
#endif
|
||||
|
||||
#ifndef FLASH_ERASE_TIME
|
||||
#define FLASH_ERASE_TIME 50
|
||||
#endif
|
||||
|
||||
struct usbd_dfu_priv {
|
||||
struct dfu_info info;
|
||||
union {
|
||||
uint32_t d32[USBD_DFU_XFER_SIZE / 4U];
|
||||
uint8_t d8[USBD_DFU_XFER_SIZE];
|
||||
} buffer;
|
||||
|
||||
uint32_t wblock_num;
|
||||
uint32_t wlength;
|
||||
uint32_t data_ptr;
|
||||
uint32_t alt_setting;
|
||||
|
||||
uint8_t dev_status[6];
|
||||
uint8_t ReservedForAlign[2];
|
||||
uint8_t dev_state;
|
||||
uint8_t manif_state;
|
||||
uint8_t firmwar_flag;
|
||||
uint8_t dfu_state;
|
||||
} g_usbd_dfu;
|
||||
|
||||
static void dfu_reset(void)
|
||||
{
|
||||
memset(&g_usbd_dfu, 0, sizeof(g_usbd_dfu));
|
||||
|
||||
g_usbd_dfu.alt_setting = 0U;
|
||||
g_usbd_dfu.data_ptr = USBD_DFU_APP_DEFAULT_ADD;
|
||||
g_usbd_dfu.wblock_num = 0U;
|
||||
g_usbd_dfu.wlength = 0U;
|
||||
|
||||
g_usbd_dfu.manif_state = DFU_MANIFEST_COMPLETE;
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_IDLE;
|
||||
|
||||
g_usbd_dfu.dev_status[0] = DFU_STATUS_OK;
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U;
|
||||
g_usbd_dfu.dev_status[4] = DFU_STATE_DFU_IDLE;
|
||||
g_usbd_dfu.dev_status[5] = 0U;
|
||||
}
|
||||
|
||||
static uint16_t dfu_getstatus(uint32_t add, uint8_t cmd, uint8_t *buffer)
|
||||
{
|
||||
switch (cmd) {
|
||||
case DFU_MEDIA_PROGRAM:
|
||||
buffer[1] = (uint8_t)FLASH_PROGRAM_TIME;
|
||||
buffer[2] = (uint8_t)(FLASH_PROGRAM_TIME << 8);
|
||||
buffer[3] = 0;
|
||||
break;
|
||||
|
||||
case DFU_MEDIA_ERASE:
|
||||
buffer[1] = (uint8_t)FLASH_ERASE_TIME;
|
||||
buffer[2] = (uint8_t)(FLASH_ERASE_TIME << 8);
|
||||
buffer[3] = 0;
|
||||
default:
|
||||
|
||||
break;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void dfu_request_detach(void)
|
||||
{
|
||||
if ((g_usbd_dfu.dev_state == DFU_STATE_DFU_IDLE) ||
|
||||
(g_usbd_dfu.dev_state == DFU_STATE_DFU_DNLOAD_SYNC) ||
|
||||
(g_usbd_dfu.dev_state == DFU_STATE_DFU_DNLOAD_IDLE) ||
|
||||
(g_usbd_dfu.dev_state == DFU_STATE_DFU_MANIFEST_SYNC) ||
|
||||
(g_usbd_dfu.dev_state == DFU_STATE_DFU_UPLOAD_IDLE)) {
|
||||
/* Update the state machine */
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_IDLE;
|
||||
g_usbd_dfu.dev_status[0] = DFU_STATUS_OK;
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U; /*bwPollTimeout=0ms*/
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
|
||||
g_usbd_dfu.dev_status[5] = 0U; /*iString*/
|
||||
g_usbd_dfu.wblock_num = 0U;
|
||||
g_usbd_dfu.wlength = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
static void dfu_request_upload(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
|
||||
{
|
||||
struct usb_setup_packet *req = setup;
|
||||
uint32_t addr;
|
||||
/* Data setup request */
|
||||
if (req->wLength > 0U) {
|
||||
if ((g_usbd_dfu.dev_state == DFU_STATE_DFU_IDLE) || (g_usbd_dfu.dev_state == DFU_STATE_DFU_UPLOAD_IDLE)) {
|
||||
/* Update the global length and block number */
|
||||
g_usbd_dfu.wblock_num = req->wValue;
|
||||
g_usbd_dfu.wlength = MIN(req->wLength, USBD_DFU_XFER_SIZE);
|
||||
|
||||
/* DFU Get Command */
|
||||
if (g_usbd_dfu.wblock_num == 0U) {
|
||||
/* Update the state machine */
|
||||
g_usbd_dfu.dev_state = (g_usbd_dfu.wlength > 3U) ? DFU_STATE_DFU_IDLE : DFU_STATE_DFU_UPLOAD_IDLE;
|
||||
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U;
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
|
||||
|
||||
/* Store the values of all supported commands */
|
||||
g_usbd_dfu.buffer.d8[0] = DFU_CMD_GETCOMMANDS;
|
||||
g_usbd_dfu.buffer.d8[1] = DFU_CMD_SETADDRESSPOINTER;
|
||||
g_usbd_dfu.buffer.d8[2] = DFU_CMD_ERASE;
|
||||
|
||||
/* Send the status data over EP0 */
|
||||
memcpy(*data, g_usbd_dfu.buffer.d8, 3);
|
||||
*len = 3;
|
||||
} else if (g_usbd_dfu.wblock_num > 1U) {
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_UPLOAD_IDLE;
|
||||
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U;
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
|
||||
|
||||
addr = ((g_usbd_dfu.wblock_num - 2U) * USBD_DFU_XFER_SIZE) + g_usbd_dfu.data_ptr;
|
||||
|
||||
/* Return the physical address where data are stored */
|
||||
dfu_read_flash((uint8_t *)addr, g_usbd_dfu.buffer.d8, g_usbd_dfu.wlength);
|
||||
|
||||
/* Send the status data over EP0 */
|
||||
memcpy(*data, g_usbd_dfu.buffer.d8, g_usbd_dfu.wlength);
|
||||
*len = g_usbd_dfu.wlength;
|
||||
} else /* unsupported g_usbd_dfu.wblock_num */
|
||||
{
|
||||
g_usbd_dfu.dev_state = DFU_STATUS_ERR_STALLEDPKT;
|
||||
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U;
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
|
||||
|
||||
/* Call the error management function (command will be NAKed */
|
||||
USB_LOG_ERR("Dfu_request_upload unsupported g_usbd_dfu.wblock_num\r\n");
|
||||
}
|
||||
}
|
||||
/* Unsupported state */
|
||||
else {
|
||||
g_usbd_dfu.wlength = 0U;
|
||||
g_usbd_dfu.wblock_num = 0U;
|
||||
|
||||
/* Call the error management function (command will be NAKed */
|
||||
USB_LOG_ERR("Dfu_request_upload unsupported state\r\n");
|
||||
}
|
||||
}
|
||||
/* No Data setup request */
|
||||
else {
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_IDLE;
|
||||
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U;
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
|
||||
}
|
||||
}
|
||||
|
||||
static void dfu_request_dnload(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
|
||||
{
|
||||
/* Data setup request */
|
||||
struct usb_setup_packet *req = setup;
|
||||
if (req->wLength > 0U) {
|
||||
if ((g_usbd_dfu.dev_state == DFU_STATE_DFU_IDLE) || (g_usbd_dfu.dev_state == DFU_STATE_DFU_DNLOAD_IDLE)) {
|
||||
/* Update the global length and block number */
|
||||
g_usbd_dfu.wblock_num = req->wValue;
|
||||
g_usbd_dfu.wlength = MIN(req->wLength, USBD_DFU_XFER_SIZE);
|
||||
|
||||
/* Update the state machine */
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_DNLOAD_SYNC;
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
|
||||
|
||||
/*!< Data has received complete */
|
||||
memcpy((uint8_t *)g_usbd_dfu.buffer.d8, (uint8_t *)*data, g_usbd_dfu.wlength);
|
||||
/*!< Set flag = 1 Write the firmware to the flash in the next dfu_request_getstatus */
|
||||
g_usbd_dfu.firmwar_flag = 1;
|
||||
}
|
||||
/* Unsupported state */
|
||||
else {
|
||||
USB_LOG_ERR("Dfu_request_dnload unsupported state\r\n");
|
||||
}
|
||||
}
|
||||
/* 0 Data DNLOAD request */
|
||||
else {
|
||||
/* End of DNLOAD operation*/
|
||||
if ((g_usbd_dfu.dev_state == DFU_STATE_DFU_DNLOAD_IDLE) || (g_usbd_dfu.dev_state == DFU_STATE_DFU_IDLE)) {
|
||||
g_usbd_dfu.manif_state = DFU_MANIFEST_IN_PROGRESS;
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_MANIFEST_SYNC;
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U;
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
|
||||
} else {
|
||||
/* Call the error management function (command will be NAKed */
|
||||
USB_LOG_ERR("Dfu_request_dnload End of DNLOAD operation but dev_state %02x \r\n", g_usbd_dfu.dev_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int8_t dfu_getstatus_special_handler(void)
|
||||
{
|
||||
uint32_t addr;
|
||||
if (g_usbd_dfu.dev_state == DFU_STATE_DFU_DNLOAD_BUSY) {
|
||||
/* Decode the Special Command */
|
||||
if (g_usbd_dfu.wblock_num == 0U) {
|
||||
if (g_usbd_dfu.wlength == 1U) {
|
||||
if (g_usbd_dfu.buffer.d8[0] == DFU_CMD_GETCOMMANDS) {
|
||||
/* Nothing to do */
|
||||
}
|
||||
} else if (g_usbd_dfu.wlength == 5U) {
|
||||
if (g_usbd_dfu.buffer.d8[0] == DFU_CMD_SETADDRESSPOINTER) {
|
||||
g_usbd_dfu.data_ptr = g_usbd_dfu.buffer.d8[1];
|
||||
g_usbd_dfu.data_ptr += (uint32_t)g_usbd_dfu.buffer.d8[2] << 8;
|
||||
g_usbd_dfu.data_ptr += (uint32_t)g_usbd_dfu.buffer.d8[3] << 16;
|
||||
g_usbd_dfu.data_ptr += (uint32_t)g_usbd_dfu.buffer.d8[4] << 24;
|
||||
} else if (g_usbd_dfu.buffer.d8[0] == DFU_CMD_ERASE) {
|
||||
g_usbd_dfu.data_ptr = g_usbd_dfu.buffer.d8[1];
|
||||
g_usbd_dfu.data_ptr += (uint32_t)g_usbd_dfu.buffer.d8[2] << 8;
|
||||
g_usbd_dfu.data_ptr += (uint32_t)g_usbd_dfu.buffer.d8[3] << 16;
|
||||
g_usbd_dfu.data_ptr += (uint32_t)g_usbd_dfu.buffer.d8[4] << 24;
|
||||
|
||||
USB_LOG_DBG("Erase start add %08x \r\n", g_usbd_dfu.data_ptr);
|
||||
/*!< Erase */
|
||||
dfu_erase_flash(g_usbd_dfu.data_ptr);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
/* Reset the global length and block number */
|
||||
g_usbd_dfu.wlength = 0U;
|
||||
g_usbd_dfu.wblock_num = 0U;
|
||||
/* Call the error management function (command will be NAKed) */
|
||||
USB_LOG_ERR("Reset the global length and block number\r\n");
|
||||
}
|
||||
}
|
||||
/* Regular Download Command */
|
||||
else {
|
||||
if (g_usbd_dfu.wblock_num > 1U) {
|
||||
/* Decode the required address */
|
||||
addr = ((g_usbd_dfu.wblock_num - 2U) * USBD_DFU_XFER_SIZE) + g_usbd_dfu.data_ptr;
|
||||
|
||||
/* Perform the write operation */
|
||||
/* Write flash */
|
||||
USB_LOG_DBG("Write start add %08x length %d\r\n", addr, g_usbd_dfu.wlength);
|
||||
dfu_write_flash(g_usbd_dfu.buffer.d8, (uint8_t *)addr, g_usbd_dfu.wlength);
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset the global length and block number */
|
||||
g_usbd_dfu.wlength = 0U;
|
||||
g_usbd_dfu.wblock_num = 0U;
|
||||
|
||||
/* Update the state machine */
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_DNLOAD_SYNC;
|
||||
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U;
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dfu_request_getstatus(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
|
||||
{
|
||||
/*!< Determine whether to leave DFU mode */
|
||||
if (g_usbd_dfu.manif_state == DFU_MANIFEST_IN_PROGRESS &&
|
||||
g_usbd_dfu.dev_state == DFU_STATE_DFU_MANIFEST_SYNC &&
|
||||
g_usbd_dfu.dev_status[1] == 0U &&
|
||||
g_usbd_dfu.dev_status[2] == 0U &&
|
||||
g_usbd_dfu.dev_status[3] == 0U &&
|
||||
g_usbd_dfu.dev_status[4] == g_usbd_dfu.dev_state) {
|
||||
g_usbd_dfu.manif_state = DFU_MANIFEST_COMPLETE;
|
||||
|
||||
if ((0x0B & DFU_MANIFEST_MASK) != 0U) {
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_MANIFEST_SYNC;
|
||||
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U;
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
|
||||
return;
|
||||
} else {
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_MANIFEST_WAIT_RESET;
|
||||
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U;
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
|
||||
/* Generate system reset to allow jumping to the user code */
|
||||
dfu_leave();
|
||||
}
|
||||
}
|
||||
|
||||
switch (g_usbd_dfu.dev_state) {
|
||||
case DFU_STATE_DFU_DNLOAD_SYNC:
|
||||
if (g_usbd_dfu.wlength != 0U) {
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_DNLOAD_BUSY;
|
||||
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U;
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
|
||||
|
||||
if ((g_usbd_dfu.wblock_num == 0U) && (g_usbd_dfu.buffer.d8[0] == DFU_CMD_ERASE)) {
|
||||
dfu_getstatus(g_usbd_dfu.data_ptr, DFU_MEDIA_ERASE, g_usbd_dfu.dev_status);
|
||||
} else {
|
||||
dfu_getstatus(g_usbd_dfu.data_ptr, DFU_MEDIA_PROGRAM, g_usbd_dfu.dev_status);
|
||||
}
|
||||
} else /* (g_usbd_dfu.wlength==0)*/
|
||||
{
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_DNLOAD_IDLE;
|
||||
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U;
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
|
||||
}
|
||||
break;
|
||||
|
||||
case DFU_STATE_DFU_MANIFEST_SYNC:
|
||||
if (g_usbd_dfu.manif_state == DFU_MANIFEST_IN_PROGRESS) {
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_MANIFEST;
|
||||
|
||||
g_usbd_dfu.dev_status[1] = 1U; /*bwPollTimeout = 1ms*/
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U;
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
|
||||
} else {
|
||||
if ((g_usbd_dfu.manif_state == DFU_MANIFEST_COMPLETE) &&
|
||||
((0x0B & DFU_MANIFEST_MASK) != 0U)) {
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_IDLE;
|
||||
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U;
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Send the status data over EP0 */
|
||||
memcpy(*data, g_usbd_dfu.dev_status, 6);
|
||||
*len = 6;
|
||||
|
||||
if (g_usbd_dfu.firmwar_flag == 1) {
|
||||
if (dfu_getstatus_special_handler() != 0) {
|
||||
USB_LOG_ERR("dfu_getstatus_special_handler error \r\n");
|
||||
}
|
||||
g_usbd_dfu.firmwar_flag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void dfu_request_clrstatus(void)
|
||||
{
|
||||
if (g_usbd_dfu.dev_state == DFU_STATE_DFU_ERROR) {
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_IDLE;
|
||||
g_usbd_dfu.dev_status[0] = DFU_STATUS_OK; /* bStatus */
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U; /* bwPollTimeout=0ms */
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state; /* bState */
|
||||
g_usbd_dfu.dev_status[5] = 0U; /* iString */
|
||||
} else {
|
||||
/* State Error */
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_ERROR;
|
||||
g_usbd_dfu.dev_status[0] = DFU_STATUS_ERR_UNKNOWN; /* bStatus */
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U; /* bwPollTimeout=0ms */
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state; /* bState */
|
||||
g_usbd_dfu.dev_status[5] = 0U; /* iString */
|
||||
}
|
||||
}
|
||||
|
||||
static void dfu_request_getstate(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
|
||||
{
|
||||
/* Return the current state of the DFU interface */
|
||||
(*data)[0] = g_usbd_dfu.dev_state;
|
||||
*len = 1;
|
||||
}
|
||||
|
||||
void dfu_request_abort(void)
|
||||
{
|
||||
if ((g_usbd_dfu.dev_state == DFU_STATE_DFU_IDLE) ||
|
||||
(g_usbd_dfu.dev_state == DFU_STATE_DFU_DNLOAD_SYNC) ||
|
||||
(g_usbd_dfu.dev_state == DFU_STATE_DFU_DNLOAD_IDLE) ||
|
||||
(g_usbd_dfu.dev_state == DFU_STATE_DFU_MANIFEST_SYNC) ||
|
||||
(g_usbd_dfu.dev_state == DFU_STATE_DFU_UPLOAD_IDLE)) {
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_IDLE;
|
||||
g_usbd_dfu.dev_status[0] = DFU_STATUS_OK;
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U; /* bwPollTimeout=0ms */
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
|
||||
g_usbd_dfu.dev_status[5] = 0U; /* iString */
|
||||
g_usbd_dfu.wblock_num = 0U;
|
||||
g_usbd_dfu.wlength = 0U;
|
||||
}
|
||||
}
|
||||
const char *usbd_dfu_state_string[] = {
|
||||
"APP_IDLE",
|
||||
"APP_DETACH",
|
||||
"DFU_IDLE",
|
||||
"DFU_DNLOAD_SYNC",
|
||||
"DFU_DNLOAD_BUSY",
|
||||
"DFU_DNLOAD_IDLE",
|
||||
"DFU_MANIFEST_SYNC",
|
||||
"DFU_MANIFEST",
|
||||
"DFU_MANIFEST_WAIT_RESET",
|
||||
"DFU_UPLOAD_IDLE",
|
||||
"DFU_ERROR"
|
||||
};
|
||||
|
||||
static int dfu_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
|
||||
{
|
||||
@@ -433,33 +30,260 @@ static int dfu_class_interface_request_handler(uint8_t busid, struct usb_setup_p
|
||||
"bRequest 0x%02x\r\n",
|
||||
setup->bRequest);
|
||||
|
||||
USB_LOG_DBG("dfu state:%s\r\n", usbd_dfu_state_string[g_usbd_dfu.dfu_state]);
|
||||
|
||||
switch (g_usbd_dfu.dfu_state) {
|
||||
case DFU_STATE_APP_IDLE:
|
||||
switch (setup->bRequest) {
|
||||
case DFU_REQUEST_DETACH:
|
||||
dfu_request_detach();
|
||||
break;
|
||||
case DFU_REQUEST_DNLOAD:
|
||||
dfu_request_dnload(setup, data, len);
|
||||
break;
|
||||
case DFU_REQUEST_UPLOAD:
|
||||
dfu_request_upload(setup, data, len);
|
||||
break;
|
||||
case DFU_REQUEST_GETSTATUS:
|
||||
dfu_request_getstatus(setup, data, len);
|
||||
break;
|
||||
case DFU_REQUEST_CLRSTATUS:
|
||||
dfu_request_clrstatus();
|
||||
(*data)[0] = DFU_STATUS_OK; /* bStatus */
|
||||
(*data)[1] = 0;
|
||||
(*data)[2] = 0;
|
||||
(*data)[3] = 0;
|
||||
(*data)[4] = g_usbd_dfu.dfu_state;
|
||||
(*data)[5] = 0; /* iString */
|
||||
*len = 6;
|
||||
break;
|
||||
case DFU_REQUEST_GETSTATE:
|
||||
dfu_request_getstate(setup, data, len);
|
||||
break;
|
||||
case DFU_REQUEST_ABORT:
|
||||
dfu_request_abort();
|
||||
(*data)[0] = g_usbd_dfu.dfu_state;
|
||||
*len = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled DFU Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case DFU_STATE_APP_DETACH:
|
||||
switch (setup->bRequest) {
|
||||
case DFU_REQUEST_GETSTATUS:
|
||||
(*data)[0] = DFU_STATUS_OK; /* bStatus */
|
||||
(*data)[1] = 0;
|
||||
(*data)[2] = 0;
|
||||
(*data)[3] = 0;
|
||||
(*data)[4] = g_usbd_dfu.dfu_state;
|
||||
(*data)[5] = 0; /* iString */
|
||||
*len = 6;
|
||||
break;
|
||||
case DFU_REQUEST_GETSTATE:
|
||||
(*data)[0] = g_usbd_dfu.dfu_state;
|
||||
*len = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case DFU_STATE_DFU_IDLE:
|
||||
switch (setup->bRequest) {
|
||||
case DFU_REQUEST_DNLOAD:
|
||||
/* We received a DOWNLOAD command. Check the length field of the request. If it is 0,
|
||||
we are done with the transfer. */
|
||||
if (setup->wLength == 0) {
|
||||
usbd_dfu_end_load();
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_MANIFEST_SYNC;
|
||||
} else {
|
||||
usbd_dfu_begin_load();
|
||||
if (usbd_dfu_write(setup->wValue, *data, setup->wLength) < 0) {
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_ERROR;
|
||||
return -1;
|
||||
} else {
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_DNLOAD_SYNC;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DFU_REQUEST_UPLOAD:
|
||||
usbd_dfu_begin_load();
|
||||
|
||||
uint16_t actual_length;
|
||||
if (usbd_dfu_read(setup->wValue, *data, setup->wLength, &actual_length) < 0) {
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_ERROR;
|
||||
return -1;
|
||||
} else {
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_UPLOAD_IDLE;
|
||||
}
|
||||
break;
|
||||
case DFU_REQUEST_ABORT:
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_IDLE;
|
||||
break;
|
||||
case DFU_REQUEST_GETSTATUS:
|
||||
(*data)[0] = DFU_STATUS_OK; /* bStatus */
|
||||
(*data)[1] = 0;
|
||||
(*data)[2] = 0;
|
||||
(*data)[3] = 0;
|
||||
(*data)[4] = g_usbd_dfu.dfu_state;
|
||||
(*data)[5] = 0; /* iString */
|
||||
*len = 6;
|
||||
break;
|
||||
case DFU_REQUEST_GETSTATE:
|
||||
(*data)[0] = g_usbd_dfu.dfu_state;
|
||||
*len = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case DFU_STATE_DFU_DNLOAD_SYNC:
|
||||
switch (setup->bRequest) {
|
||||
case DFU_REQUEST_GETSTATUS:
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_DNLOAD_BUSY;
|
||||
|
||||
(*data)[0] = DFU_STATUS_OK; /* bStatus */
|
||||
(*data)[1] = 0;
|
||||
(*data)[2] = 0;
|
||||
(*data)[3] = 0;
|
||||
(*data)[4] = g_usbd_dfu.dfu_state;
|
||||
(*data)[5] = 0; /* iString */
|
||||
*len = 6;
|
||||
break;
|
||||
case DFU_REQUEST_GETSTATE:
|
||||
(*data)[0] = g_usbd_dfu.dfu_state;
|
||||
*len = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case DFU_STATE_DFU_DNLOAD_BUSY:
|
||||
switch (setup->bRequest) {
|
||||
case DFU_REQUEST_GETSTATUS:
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_DNLOAD_IDLE;
|
||||
|
||||
(*data)[0] = DFU_STATUS_OK; /* bStatus */
|
||||
(*data)[1] = 0;
|
||||
(*data)[2] = 0;
|
||||
(*data)[3] = 0;
|
||||
(*data)[4] = g_usbd_dfu.dfu_state;
|
||||
(*data)[5] = 0; /* iString */
|
||||
*len = 6;
|
||||
break;
|
||||
case DFU_REQUEST_GETSTATE:
|
||||
(*data)[0] = g_usbd_dfu.dfu_state;
|
||||
*len = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case DFU_STATE_DFU_DNLOAD_IDLE:
|
||||
switch (setup->bRequest) {
|
||||
case DFU_REQUEST_DNLOAD:
|
||||
/* We received a DOWNLOAD command. Check the length field of the request. If it is 0,
|
||||
we are done with the transfer. */
|
||||
if (setup->wLength == 0) {
|
||||
usbd_dfu_end_load();
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_MANIFEST_SYNC;
|
||||
} else {
|
||||
if (usbd_dfu_write(setup->wValue, *data, setup->wLength) < 0) {
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_ERROR;
|
||||
return -1;
|
||||
} else {
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_DNLOAD_SYNC;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case DFU_REQUEST_ABORT:
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_IDLE;
|
||||
break;
|
||||
case DFU_REQUEST_GETSTATUS:
|
||||
(*data)[0] = DFU_STATUS_OK; /* bStatus */
|
||||
(*data)[1] = 0;
|
||||
(*data)[2] = 0;
|
||||
(*data)[3] = 0;
|
||||
(*data)[4] = g_usbd_dfu.dfu_state;
|
||||
(*data)[5] = 0; /* iString */
|
||||
*len = 6;
|
||||
break;
|
||||
case DFU_REQUEST_GETSTATE:
|
||||
(*data)[0] = g_usbd_dfu.dfu_state;
|
||||
*len = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case DFU_STATE_DFU_UPLOAD_IDLE:
|
||||
switch (setup->bRequest) {
|
||||
case DFU_REQUEST_UPLOAD: {
|
||||
uint16_t actual_length;
|
||||
if (usbd_dfu_read(setup->wValue, *data, setup->wLength, &actual_length) < 0) {
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_ERROR;
|
||||
return -1;
|
||||
} else {
|
||||
if (actual_length < setup->wLength) {
|
||||
usbd_dfu_end_load();
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_IDLE;
|
||||
} else {
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_UPLOAD_IDLE;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case DFU_REQUEST_ABORT:
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_IDLE;
|
||||
break;
|
||||
case DFU_REQUEST_GETSTATUS:
|
||||
(*data)[0] = DFU_STATUS_OK; /* bStatus */
|
||||
(*data)[1] = 0;
|
||||
(*data)[2] = 0;
|
||||
(*data)[3] = 0;
|
||||
(*data)[4] = g_usbd_dfu.dfu_state;
|
||||
(*data)[5] = 0; /* iString */
|
||||
*len = 6;
|
||||
break;
|
||||
case DFU_REQUEST_GETSTATE:
|
||||
(*data)[0] = g_usbd_dfu.dfu_state;
|
||||
*len = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case DFU_STATE_DFU_MANIFEST_SYNC:
|
||||
switch (setup->bRequest) {
|
||||
case DFU_REQUEST_GETSTATUS:
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_MANIFEST_WAIT_RESET;
|
||||
|
||||
(*data)[0] = DFU_STATUS_OK; /* bStatus */
|
||||
(*data)[1] = 0;
|
||||
(*data)[2] = 0;
|
||||
(*data)[3] = 0;
|
||||
(*data)[4] = g_usbd_dfu.dfu_state;
|
||||
(*data)[5] = 0; /* iString */
|
||||
*len = 6;
|
||||
|
||||
usbd_dfu_reset();
|
||||
break;
|
||||
case DFU_REQUEST_GETSTATE:
|
||||
(*data)[0] = g_usbd_dfu.dfu_state;
|
||||
*len = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case DFU_STATE_DFU_ERROR:
|
||||
switch (setup->bRequest) {
|
||||
case DFU_REQUEST_CLRSTATUS:
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_IDLE;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
USB_LOG_WRN("Invalid dfu state %s\r\n", usbd_dfu_state_string[g_usbd_dfu.dfu_state]);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -467,7 +291,7 @@ static void dfu_notify_handler(uint8_t busid, uint8_t event, void *arg)
|
||||
{
|
||||
switch (event) {
|
||||
case USBD_EVENT_RESET:
|
||||
dfu_reset();
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_IDLE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -484,21 +308,29 @@ struct usbd_interface *usbd_dfu_init_intf(struct usbd_interface *intf)
|
||||
return intf;
|
||||
}
|
||||
|
||||
__WEAK uint8_t *dfu_read_flash(uint8_t *src, uint8_t *dest, uint32_t len)
|
||||
uint8_t usbd_dfu_get_state(void)
|
||||
{
|
||||
return dest;
|
||||
return g_usbd_dfu.dfu_state;
|
||||
}
|
||||
|
||||
__WEAK uint16_t dfu_write_flash(uint8_t *src, uint8_t *dest, uint32_t len)
|
||||
__WEAK void usbd_dfu_begin_load(void)
|
||||
{
|
||||
}
|
||||
|
||||
__WEAK void usbd_dfu_end_load(void)
|
||||
{
|
||||
}
|
||||
|
||||
__WEAK void usbd_dfu_reset(void)
|
||||
{
|
||||
}
|
||||
|
||||
__WEAK int usbd_dfu_write(uint16_t value, const uint8_t *data, uint16_t length)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
__WEAK uint16_t dfu_erase_flash(uint32_t add)
|
||||
__WEAK int usbd_dfu_read(uint16_t value, const uint8_t *data, uint16_t length, uint16_t *actual_length)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
__WEAK void dfu_leave(void)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022, sakumisu
|
||||
* Copyright (c) 2022 ~ 2026, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -14,12 +14,14 @@ extern "C" {
|
||||
|
||||
/* Init dfu interface driver */
|
||||
struct usbd_interface *usbd_dfu_init_intf(struct usbd_interface *intf);
|
||||
uint8_t usbd_dfu_get_state(void);
|
||||
|
||||
void usbd_dfu_begin_load(void);
|
||||
void usbd_dfu_end_load(void);
|
||||
void usbd_dfu_reset(void);
|
||||
int usbd_dfu_write(uint16_t value, const uint8_t *data, uint16_t length);
|
||||
int usbd_dfu_read(uint16_t value, const uint8_t *data, uint16_t length, uint16_t *actual_length);
|
||||
|
||||
/* Interface functions that need to be implemented by the user */
|
||||
uint8_t *dfu_read_flash(uint8_t *src, uint8_t *dest, uint32_t len);
|
||||
uint16_t dfu_write_flash(uint8_t *src, uint8_t *dest, uint32_t len);
|
||||
uint16_t dfu_erase_flash(uint32_t add);
|
||||
void dfu_leave(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -41,7 +41,6 @@ static int hid_class_interface_request_handler(uint8_t busid, struct usb_setup_p
|
||||
break;
|
||||
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled HID Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -89,7 +89,6 @@ static int msc_storage_class_interface_request_handler(uint8_t busid, struct usb
|
||||
break;
|
||||
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled MSC Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "usbh_ch34x.h"
|
||||
|
||||
#undef USB_DBG_TAG
|
||||
#define USB_DBG_TAG "usbh_ch43x"
|
||||
#define USB_DBG_TAG "usbh_ch34x"
|
||||
#include "usb_log.h"
|
||||
|
||||
struct usbh_ch34x {
|
||||
|
||||
184
class/vendor/display/usbd_display.c
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright (c) 2026, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "usbd_core.h"
|
||||
#include "usbd_display.h"
|
||||
#include "chry_mempool.h"
|
||||
|
||||
struct usbd_disp_frame_header {
|
||||
uint16_t crc16; //payload crc16
|
||||
uint8_t type; //raw rgb,yuv,jpg,other
|
||||
uint8_t cmd;
|
||||
uint16_t x; //32bit
|
||||
uint16_t y;
|
||||
uint16_t width; //32bit
|
||||
uint16_t height;
|
||||
uint32_t frame_id : 10;
|
||||
uint32_t payload_total : 22; //payload max 4MB
|
||||
} __PACKED;
|
||||
|
||||
struct usbd_display_priv {
|
||||
struct chry_mempool pool;
|
||||
struct usbd_endpoint out_ep;
|
||||
struct usbd_endpoint in_ep;
|
||||
struct usbd_display_frame *current_frame;
|
||||
} g_usbd_display;
|
||||
|
||||
int usbd_display_frame_create(struct usbd_display_frame *frame, uint32_t count)
|
||||
{
|
||||
return chry_mempool_create(&g_usbd_display.pool, frame, sizeof(struct usbd_display_frame), count);
|
||||
}
|
||||
|
||||
struct usbd_display_frame *usbd_display_frame_alloc(void)
|
||||
{
|
||||
return (struct usbd_display_frame *)chry_mempool_alloc(&g_usbd_display.pool);
|
||||
}
|
||||
|
||||
int usbd_display_frame_free(struct usbd_display_frame *frame)
|
||||
{
|
||||
return chry_mempool_free(&g_usbd_display.pool, (uintptr_t *)frame);
|
||||
}
|
||||
|
||||
int usbd_display_frame_send(struct usbd_display_frame *frame)
|
||||
{
|
||||
return chry_mempool_send(&g_usbd_display.pool, (uintptr_t *)frame);
|
||||
}
|
||||
|
||||
int usbd_display_frame_recv(struct usbd_display_frame **frame, uint32_t timeout)
|
||||
{
|
||||
return chry_mempool_recv(&g_usbd_display.pool, (uintptr_t **)frame, timeout);
|
||||
}
|
||||
|
||||
uint8_t usb_dispay_dummy[512];
|
||||
volatile uint32_t usb_display_buf_offset;
|
||||
volatile bool usb_display_ignore_frame;
|
||||
|
||||
static void display_notify_handler(uint8_t busid, uint8_t event, void *arg)
|
||||
{
|
||||
switch (event) {
|
||||
case USBD_EVENT_RESET:
|
||||
break;
|
||||
case USBD_EVENT_CONFIGURED:
|
||||
usb_display_buf_offset = 0;
|
||||
usb_display_ignore_frame = true;
|
||||
g_usbd_display.current_frame = NULL;
|
||||
usbd_ep_start_read(busid, g_usbd_display.out_ep.ep_addr, usb_dispay_dummy, usbd_get_ep_mps(0, g_usbd_display.out_ep.ep_addr));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void usbd_display_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
|
||||
{
|
||||
if (usb_display_ignore_frame) {
|
||||
// alloc frame for next at the end of current frame
|
||||
if ((nbytes % usbd_get_ep_mps(0, g_usbd_display.out_ep.ep_addr)) || (nbytes == 0)) {
|
||||
if (g_usbd_display.current_frame == NULL) {
|
||||
g_usbd_display.current_frame = usbd_display_frame_alloc();
|
||||
if (g_usbd_display.current_frame) {
|
||||
usb_display_ignore_frame = false;
|
||||
usb_display_buf_offset = 0;
|
||||
|
||||
goto get_frame;
|
||||
} else {
|
||||
goto drop_frame;
|
||||
}
|
||||
} else {
|
||||
usb_display_ignore_frame = false;
|
||||
usb_display_buf_offset = 0;
|
||||
|
||||
goto get_frame;
|
||||
}
|
||||
} else {
|
||||
goto drop_frame;
|
||||
}
|
||||
} else {
|
||||
struct usbd_disp_frame_header *header = (struct usbd_disp_frame_header *)&g_usbd_display.current_frame->frame_buf[0];
|
||||
struct usbd_display_frame *frame;
|
||||
|
||||
if (header->payload_total > g_usbd_display.current_frame->frame_bufsize) {
|
||||
USB_LOG_ERR("frame overflow, drop it\r\n");
|
||||
usb_display_ignore_frame = true;
|
||||
|
||||
goto drop_frame;
|
||||
}
|
||||
|
||||
usb_display_buf_offset += nbytes;
|
||||
|
||||
if ((nbytes % usbd_get_ep_mps(0, g_usbd_display.out_ep.ep_addr)) || (nbytes == 0)) {
|
||||
frame = g_usbd_display.current_frame;
|
||||
g_usbd_display.current_frame = NULL;
|
||||
|
||||
frame->frame_format = header->type;
|
||||
frame->frame_size = header->payload_total;
|
||||
usbd_display_frame_send(frame);
|
||||
|
||||
g_usbd_display.current_frame = usbd_display_frame_alloc();
|
||||
if (g_usbd_display.current_frame) {
|
||||
usb_display_ignore_frame = false;
|
||||
usb_display_buf_offset = 0;
|
||||
|
||||
goto get_frame;
|
||||
} else {
|
||||
usb_display_ignore_frame = true;
|
||||
|
||||
goto drop_frame;
|
||||
}
|
||||
} else {
|
||||
goto get_frame;
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
drop_frame:
|
||||
// drop current frame
|
||||
usbd_ep_start_read(busid, g_usbd_display.out_ep.ep_addr, usb_dispay_dummy, usbd_get_ep_mps(0, g_usbd_display.out_ep.ep_addr));
|
||||
return;
|
||||
get_frame:
|
||||
usbd_ep_start_read(busid, g_usbd_display.out_ep.ep_addr, &g_usbd_display.current_frame->frame_buf[usb_display_buf_offset], 16384);
|
||||
return;
|
||||
}
|
||||
|
||||
void usbd_display_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
|
||||
{
|
||||
}
|
||||
|
||||
struct usbd_interface *usbd_display_init_intf(struct usbd_interface *intf,
|
||||
const uint8_t out_ep,
|
||||
const uint8_t in_ep,
|
||||
struct usbd_display_frame *frame,
|
||||
uint32_t count)
|
||||
{
|
||||
intf->class_interface_handler = NULL;
|
||||
intf->class_endpoint_handler = NULL;
|
||||
intf->vendor_handler = NULL;
|
||||
intf->notify_handler = display_notify_handler;
|
||||
|
||||
g_usbd_display.out_ep.ep_addr = out_ep;
|
||||
g_usbd_display.out_ep.ep_cb = usbd_display_bulk_out;
|
||||
g_usbd_display.in_ep.ep_addr = in_ep;
|
||||
g_usbd_display.in_ep.ep_cb = usbd_display_bulk_in;
|
||||
usbd_add_endpoint(0, &g_usbd_display.out_ep);
|
||||
usbd_add_endpoint(0, &g_usbd_display.in_ep);
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
USB_ASSERT_MSG(frame[i].frame_bufsize % 16384, "frame_bufsize must be the multiple of 16384");
|
||||
}
|
||||
|
||||
usbd_display_frame_create(frame, count);
|
||||
return intf;
|
||||
}
|
||||
|
||||
int usbd_display_dequeue(struct usbd_display_frame **frame, uint32_t timeout)
|
||||
{
|
||||
return usbd_display_frame_recv(frame, timeout);
|
||||
}
|
||||
|
||||
int usbd_display_enqueue(struct usbd_display_frame *frame)
|
||||
{
|
||||
return usbd_display_frame_free(frame);
|
||||
}
|
||||
39
class/vendor/display/usbd_display.h
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2026, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef USBD_DISPLAY_H
|
||||
#define USBD_DISPLAY_H
|
||||
|
||||
#define USBD_DISPLAY_TYPE_RGB565 0
|
||||
#define USBD_DISPLAY_TYPE_RGB888 1
|
||||
#define USBD_DISPLAY_TYPE_YUV420 2
|
||||
#define USBD_DISPLAY_TYPE_JPG 3
|
||||
|
||||
struct usbd_display_frame {
|
||||
uint8_t *frame_buf;
|
||||
uint32_t frame_bufsize;
|
||||
uint32_t frame_format;
|
||||
uint32_t frame_size;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Init display interface driver */
|
||||
struct usbd_interface *usbd_display_init_intf(struct usbd_interface *intf,
|
||||
const uint8_t out_ep,
|
||||
const uint8_t in_ep,
|
||||
struct usbd_display_frame *frame,
|
||||
uint32_t count);
|
||||
|
||||
int usbd_display_dequeue(struct usbd_display_frame **frame, uint32_t timeout);
|
||||
int usbd_display_enqueue(struct usbd_display_frame *frame);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* USBD_DISPLAY_H */
|
||||
@@ -44,7 +44,6 @@ static int usbd_video_control_request_handler(uint8_t busid, struct usb_setup_pa
|
||||
case VIDEO_REQUEST_GET_INFO:
|
||||
break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -58,7 +57,6 @@ static int usbd_video_control_request_handler(uint8_t busid, struct usb_setup_pa
|
||||
case VIDEO_REQUEST_GET_INFO:
|
||||
break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -91,7 +89,6 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
|
||||
*len = 1;
|
||||
break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -127,7 +124,6 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
|
||||
*len = 4;
|
||||
} break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -163,7 +159,6 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
|
||||
*len = 2;
|
||||
} break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -199,7 +194,6 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
|
||||
*len = 2;
|
||||
} break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -235,7 +229,6 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
|
||||
*len = 2;
|
||||
} break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -247,16 +240,13 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
|
||||
*len = 2;
|
||||
} break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class control selector 0x%02x\r\n", control_selector);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
USB_LOG_WRN("Unhandled Video Class wTerminalType 0x%02x\r\n", entity_info->wTerminalType);
|
||||
return -2;
|
||||
}
|
||||
break;
|
||||
@@ -298,7 +288,6 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
|
||||
*len = 2;
|
||||
} break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -337,7 +326,6 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
|
||||
*len = 2;
|
||||
} break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -373,7 +361,6 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
|
||||
*len = 2;
|
||||
} break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -409,7 +396,6 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
|
||||
*len = 2;
|
||||
} break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -440,7 +426,6 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
|
||||
*len = 2;
|
||||
} break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -471,7 +456,6 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
|
||||
*len = 2;
|
||||
} break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -502,7 +486,6 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
|
||||
*len = 2;
|
||||
} break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -538,7 +521,6 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
|
||||
*len = 2;
|
||||
} break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -550,13 +532,11 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
|
||||
*len = 1;
|
||||
} break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
g_usbd_video[busid].error_code = 0x06;
|
||||
USB_LOG_WRN("Unhandled Video Class control selector 0x%02x\r\n", control_selector);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -606,7 +586,6 @@ static int usbd_video_stream_request_handler(uint8_t busid, struct usb_setup_pac
|
||||
break;
|
||||
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -638,7 +617,6 @@ static int usbd_video_stream_request_handler(uint8_t busid, struct usb_setup_pac
|
||||
break;
|
||||
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -653,7 +631,6 @@ static int usbd_video_stream_request_handler(uint8_t busid, struct usb_setup_pac
|
||||
*len = 1;
|
||||
break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -365,14 +365,9 @@ static int rndis_set_cmd_handler(uint8_t *data, uint32_t len)
|
||||
|
||||
switch (cmd->Oid) {
|
||||
case OID_GEN_RNDIS_CONFIG_PARAMETER:
|
||||
param = (rndis_config_parameter_t *)((uint8_t *)&(cmd->RequestId) + cmd->InformationBufferOffset);
|
||||
USB_LOG_WRN("RNDIS cfg param: NameOfs=%d, NameLen=%d, ValueOfs=%d, ValueLen=%d\r\n",
|
||||
param->ParameterNameOffset, param->ParameterNameLength,
|
||||
param->ParameterValueOffset, param->ParameterValueLength);
|
||||
break;
|
||||
case OID_GEN_CURRENT_PACKET_FILTER:
|
||||
if (cmd->InformationBufferLength < sizeof(g_usbd_rndis.net_filter)) {
|
||||
USB_LOG_WRN("PACKET_FILTER!\r\n");
|
||||
resp->Status = RNDIS_STATUS_INVALID_DATA;
|
||||
} else {
|
||||
uint32_t *filter;
|
||||
|
||||
@@ -1,372 +0,0 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file : main.c
|
||||
* @brief : Main program body
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© Copyright (c) 2021 STMicroelectronics.
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
* This software component is licensed by ST under Ultimate Liberty license
|
||||
* SLA0044, the "License"; You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at:
|
||||
* www.st.com/SLA0044
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "main.h"
|
||||
|
||||
/* Private includes ----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Includes */
|
||||
#include "usbd_core.h"
|
||||
#include "usb_dfu.h"
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PTD */
|
||||
|
||||
/* USER CODE END PTD */
|
||||
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PD */
|
||||
/* USER CODE END PD */
|
||||
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PM */
|
||||
|
||||
/* USER CODE END PM */
|
||||
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
UART_HandleTypeDef huart1;
|
||||
|
||||
PCD_HandleTypeDef hpcd_USB_FS;
|
||||
|
||||
/* USER CODE BEGIN PV */
|
||||
|
||||
/* USER CODE END PV */
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
void SystemClock_Config(void);
|
||||
static void MX_GPIO_Init(void);
|
||||
static void MX_USART1_UART_Init(void);
|
||||
static void MX_USB_PCD_Init(void);
|
||||
/* USER CODE BEGIN PFP */
|
||||
typedef void (*pFunction)(void);
|
||||
static void jump_app(void)
|
||||
{
|
||||
pFunction JumpToApplication;
|
||||
uint32_t JumpAddress;
|
||||
|
||||
if (((*(__IO uint32_t *)USBD_DFU_APP_DEFAULT_ADD) & 0x2FFFB000) == 0x20000000)
|
||||
{
|
||||
/* Jump to user application */
|
||||
/*!< Jump to app reset_handler */
|
||||
JumpAddress = *(__IO uint32_t *)(USBD_DFU_APP_DEFAULT_ADD + 4);
|
||||
JumpToApplication = (pFunction)JumpAddress;
|
||||
|
||||
/* Initialize user application's Stack Pointer */
|
||||
__set_MSP(*(__IO uint32_t *)USBD_DFU_APP_DEFAULT_ADD);
|
||||
JumpToApplication();
|
||||
}
|
||||
}
|
||||
/* USER CODE END PFP */
|
||||
|
||||
/* Private user code ---------------------------------------------------------*/
|
||||
/* USER CODE BEGIN 0 */
|
||||
int fputc(int ch, FILE *f)
|
||||
{
|
||||
while ((USART1->SR & USART_SR_TXE) == 0)
|
||||
;
|
||||
USART1->DR = ch;
|
||||
return ch;
|
||||
}
|
||||
|
||||
void usb_dc_low_level_init(void)
|
||||
{
|
||||
/* Peripheral clock enable */
|
||||
__HAL_RCC_USB_CLK_ENABLE();
|
||||
/* USB interrupt Init */
|
||||
HAL_NVIC_SetPriority(USB_LP_CAN1_RX0_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
|
||||
|
||||
}
|
||||
|
||||
uint8_t *dfu_read_flash(uint8_t *src, uint8_t *dest, uint32_t len)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
uint8_t *psrc = src;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
dest[i] = *psrc++;
|
||||
}
|
||||
/* Return a valid address to avoid HardFault */
|
||||
return (uint8_t *)(dest);
|
||||
}
|
||||
|
||||
uint16_t dfu_write_flash(uint8_t *src, uint8_t *dest, uint32_t len)
|
||||
{
|
||||
HAL_FLASH_Unlock();
|
||||
uint32_t i = 0;
|
||||
|
||||
for (i = 0; i < len; i += 4)
|
||||
{
|
||||
/* Device voltage range supposed to be [2.7V to 3.6V], the operation will
|
||||
* be done by byte */
|
||||
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, (uint32_t)(dest + i),
|
||||
*(uint32_t *)(src + i)) == HAL_OK)
|
||||
{
|
||||
/* Check the written value */
|
||||
if (*(uint32_t *)(src + i) != *(uint32_t *)(dest + i))
|
||||
{
|
||||
/* Flash content doesn't match SRAM content */
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Error occurred while writing data in Flash memory */
|
||||
return (2);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t dfu_erase_flash(uint32_t add)
|
||||
{
|
||||
HAL_FLASH_Unlock();
|
||||
uint32_t PageError;
|
||||
/* Variable contains Flash operation status */
|
||||
HAL_StatusTypeDef status;
|
||||
FLASH_EraseInitTypeDef eraseinitstruct;
|
||||
|
||||
eraseinitstruct.TypeErase = FLASH_TYPEERASE_PAGES;
|
||||
eraseinitstruct.PageAddress = add;
|
||||
eraseinitstruct.NbPages = 1U;
|
||||
status = HAL_FLASHEx_Erase(&eraseinitstruct, &PageError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dfu_leave(void)
|
||||
{
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
/* USER CODE END 0 */
|
||||
|
||||
/**
|
||||
* @brief The application entry point.
|
||||
* @retval int
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
/* USER CODE BEGIN 1 */
|
||||
jump_app();
|
||||
/* USER CODE END 1 */
|
||||
|
||||
/* MCU Configuration--------------------------------------------------------*/
|
||||
|
||||
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
|
||||
HAL_Init();
|
||||
|
||||
/* USER CODE BEGIN Init */
|
||||
|
||||
/* USER CODE END Init */
|
||||
|
||||
/* Configure the system clock */
|
||||
SystemClock_Config();
|
||||
|
||||
/* USER CODE BEGIN SysInit */
|
||||
|
||||
/* USER CODE END SysInit */
|
||||
|
||||
/* Initialize all configured peripherals */
|
||||
MX_GPIO_Init();
|
||||
MX_USART1_UART_Init();
|
||||
//MX_USB_PCD_Init();
|
||||
/* USER CODE BEGIN 2 */
|
||||
|
||||
|
||||
// extern void cdc_acm_msc_init(void);
|
||||
// cdc_acm_msc_init();
|
||||
extern void dfu_flash_init(void);
|
||||
dfu_flash_init();
|
||||
|
||||
/* USER CODE END 2 */
|
||||
|
||||
/* Infinite loop */
|
||||
/* USER CODE BEGIN WHILE */
|
||||
while (1) {
|
||||
/* USER CODE END WHILE */
|
||||
|
||||
/* USER CODE BEGIN 3 */
|
||||
// extern void cdc_acm_data_send_with_dtr_test(void);
|
||||
// cdc_acm_data_send_with_dtr_test();
|
||||
// HAL_Delay(100);
|
||||
}
|
||||
/* USER CODE END 3 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief System Clock Configuration
|
||||
* @retval None
|
||||
*/
|
||||
void SystemClock_Config(void)
|
||||
{
|
||||
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
|
||||
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
|
||||
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
|
||||
|
||||
/** Initializes the RCC Oscillators according to the specified parameters
|
||||
* in the RCC_OscInitTypeDef structure.
|
||||
*/
|
||||
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
|
||||
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
|
||||
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
|
||||
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
|
||||
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
|
||||
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
|
||||
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
|
||||
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
/** Initializes the CPU, AHB and APB buses clocks
|
||||
*/
|
||||
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|
||||
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
|
||||
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
|
||||
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
|
||||
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
|
||||
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
|
||||
|
||||
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB;
|
||||
PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_PLL_DIV1_5;
|
||||
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USART1 Initialization Function
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
static void MX_USART1_UART_Init(void)
|
||||
{
|
||||
|
||||
/* USER CODE BEGIN USART1_Init 0 */
|
||||
|
||||
/* USER CODE END USART1_Init 0 */
|
||||
|
||||
/* USER CODE BEGIN USART1_Init 1 */
|
||||
|
||||
/* USER CODE END USART1_Init 1 */
|
||||
huart1.Instance = USART1;
|
||||
huart1.Init.BaudRate = 115200;
|
||||
huart1.Init.WordLength = UART_WORDLENGTH_8B;
|
||||
huart1.Init.StopBits = UART_STOPBITS_1;
|
||||
huart1.Init.Parity = UART_PARITY_NONE;
|
||||
huart1.Init.Mode = UART_MODE_TX_RX;
|
||||
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
|
||||
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
|
||||
if (HAL_UART_Init(&huart1) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
/* USER CODE BEGIN USART1_Init 2 */
|
||||
|
||||
/* USER CODE END USART1_Init 2 */
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USB Initialization Function
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
static void MX_USB_PCD_Init(void)
|
||||
{
|
||||
|
||||
/* USER CODE BEGIN USB_Init 0 */
|
||||
|
||||
/* USER CODE END USB_Init 0 */
|
||||
|
||||
/* USER CODE BEGIN USB_Init 1 */
|
||||
|
||||
/* USER CODE END USB_Init 1 */
|
||||
hpcd_USB_FS.Instance = USB;
|
||||
hpcd_USB_FS.Init.dev_endpoints = 8;
|
||||
hpcd_USB_FS.Init.speed = PCD_SPEED_FULL;
|
||||
hpcd_USB_FS.Init.low_power_enable = DISABLE;
|
||||
hpcd_USB_FS.Init.lpm_enable = DISABLE;
|
||||
hpcd_USB_FS.Init.battery_charging_enable = DISABLE;
|
||||
if (HAL_PCD_Init(&hpcd_USB_FS) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
/* USER CODE BEGIN USB_Init 2 */
|
||||
|
||||
/* USER CODE END USB_Init 2 */
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief GPIO Initialization Function
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
static void MX_GPIO_Init(void)
|
||||
{
|
||||
|
||||
/* GPIO Ports Clock Enable */
|
||||
__HAL_RCC_GPIOD_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN 4 */
|
||||
|
||||
/* USER CODE END 4 */
|
||||
|
||||
/**
|
||||
* @brief This function is executed in case of error occurrence.
|
||||
* @retval None
|
||||
*/
|
||||
void Error_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN Error_Handler_Debug */
|
||||
/* User can add his own implementation to report the HAL error return state */
|
||||
__disable_irq();
|
||||
while (1) {
|
||||
}
|
||||
/* USER CODE END Error_Handler_Debug */
|
||||
}
|
||||
|
||||
#ifdef USE_FULL_ASSERT
|
||||
/**
|
||||
* @brief Reports the name of the source file and the source line number
|
||||
* where the assert_param error has occurred.
|
||||
* @param file: pointer to the source file name
|
||||
* @param line: assert_param error line source number
|
||||
* @retval None
|
||||
*/
|
||||
void assert_failed(uint8_t *file, uint32_t line)
|
||||
{
|
||||
/* USER CODE BEGIN 6 */
|
||||
/* User can add his own implementation to report the file name and line number,
|
||||
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
|
||||
/* USER CODE END 6 */
|
||||
}
|
||||
#endif /* USE_FULL_ASSERT */
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
* Copyright (c) 2022 ~ 2026, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -7,13 +7,13 @@
|
||||
#include "usbd_dfu.h"
|
||||
|
||||
#define USBD_VID 0x0483
|
||||
#define USBD_PID 0xDF11
|
||||
#define USBD_PID 0xdf11
|
||||
#define USBD_MAX_POWER 100
|
||||
#define USBD_LANGID_STRING 1033
|
||||
|
||||
#define FLASH_DESC_STR "@Internal Flash /0x08000000/16*001Ka,112*01Kg"
|
||||
#define USB_CONFIG_SIZE (9 + DFU_DESCRIPTOR_LEN)
|
||||
|
||||
#define USB_CONFIG_SIZE (9 + 9 + 9)
|
||||
#define FLASH_DESC_STR "@Internal Flash /0x08000000/16*128Kg"
|
||||
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0200, 0x01)
|
||||
@@ -21,7 +21,7 @@ static const uint8_t device_descriptor[] = {
|
||||
|
||||
static const uint8_t config_descriptor[] = {
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
DFU_DESCRIPTOR_INIT()
|
||||
DFU_DESCRIPTOR_INIT(4)
|
||||
};
|
||||
|
||||
static const uint8_t device_quality_descriptor[] = {
|
||||
@@ -45,6 +45,7 @@ static const char *string_descriptors[] = {
|
||||
"CherryUSB", /* Manufacturer */
|
||||
"CherryUSB DFU DEMO", /* Product */
|
||||
"2022123456", /* Serial Number */
|
||||
FLASH_DESC_STR
|
||||
};
|
||||
|
||||
static const uint8_t *device_descriptor_callback(uint8_t speed)
|
||||
@@ -64,13 +65,14 @@ static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
|
||||
|
||||
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
|
||||
{
|
||||
if (index > 3) {
|
||||
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return string_descriptors[index];
|
||||
}
|
||||
|
||||
const struct usb_descriptor dfu_flash_descriptor = {
|
||||
const struct usb_descriptor dfu_descriptor = {
|
||||
.device_descriptor_callback = device_descriptor_callback,
|
||||
.config_descriptor_callback = config_descriptor_callback,
|
||||
.device_quality_descriptor_callback = device_quality_descriptor_callback,
|
||||
@@ -104,10 +106,52 @@ static void usbd_event_handler(uint8_t busid, uint8_t event)
|
||||
|
||||
struct usbd_interface intf0;
|
||||
|
||||
void dfu_flash_init(uint8_t busid, uintptr_t reg_base)
|
||||
void dfu_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
usbd_desc_register(busid, &dfu_flash_descriptor);
|
||||
usbd_desc_register(busid, &dfu_descriptor);
|
||||
|
||||
usbd_add_interface(busid, usbd_dfu_init_intf(&intf0));
|
||||
usbd_initialize(busid, reg_base, usbd_event_handler);
|
||||
}
|
||||
|
||||
volatile uint32_t flash_start_address;
|
||||
|
||||
void usbd_dfu_begin_load(void)
|
||||
{
|
||||
flash_start_address = 0x08000000;
|
||||
}
|
||||
|
||||
void usbd_dfu_end_load(void)
|
||||
{
|
||||
}
|
||||
|
||||
void usbd_dfu_reset(void)
|
||||
{
|
||||
//NVIC_SystemReset();
|
||||
}
|
||||
|
||||
int usbd_dfu_write(uint16_t value, const uint8_t *data, uint16_t length)
|
||||
{
|
||||
//usb_hexdump(data, length);
|
||||
|
||||
// patch for stm32 special command
|
||||
#if 1
|
||||
if (value == 0) {
|
||||
if (data[0] == DFU_SPECIAL_CMD_SET_ADDRESS_POINTER) {
|
||||
memcpy((uint8_t *)&flash_start_address, data, 4);
|
||||
} else if (data[0] == DFU_SPECIAL_CMD_ERASE) {
|
||||
memcpy((uint8_t *)&flash_start_address, data, 4);
|
||||
}
|
||||
} else if (value > 1) {
|
||||
uint32_t addr = (value - 2) * CONFIG_USBDEV_REQUEST_BUFFER_LEN + flash_start_address;
|
||||
}
|
||||
#else
|
||||
flash_start_address += length;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_dfu_read(uint16_t value, const uint8_t *data, uint16_t length, uint16_t *actual_length)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
3
demo/display/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
Thanks to https://github.com/chuanjinpang/win10_idd_xfz1986_usb_graphic_driver_display project.
|
||||
|
||||
Install tools/display/xfz1986_usb_graphic_250224_rc_sign.exe in windows before use.
|
||||
146
demo/display/usbdisplay_template.c
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (c) 2026, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbd_core.h"
|
||||
#include "usbd_display.h"
|
||||
|
||||
#define DISPLAY_IN_EP 0x81
|
||||
#define DISPLAY_OUT_EP 0x02
|
||||
|
||||
#define USBD_VID 0x303A
|
||||
#define USBD_PID 0x2987
|
||||
#define USBD_MAX_POWER 100
|
||||
#define USBD_LANGID_STRING 1033
|
||||
|
||||
#define USB_CONFIG_SIZE (9 + 9 + 7 + 7)
|
||||
|
||||
#ifdef CONFIG_USB_HS
|
||||
#define DISPLAY_EP_MPS 512
|
||||
#else
|
||||
#define DISPLAY_EP_MPS 64
|
||||
#endif
|
||||
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0101, 0x01)
|
||||
};
|
||||
|
||||
static const uint8_t config_descriptor[] = {
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xff, 0x00, 0x00, 0x00),
|
||||
USB_ENDPOINT_DESCRIPTOR_INIT(DISPLAY_IN_EP, 0x02, DISPLAY_EP_MPS, 0x00),
|
||||
USB_ENDPOINT_DESCRIPTOR_INIT(DISPLAY_OUT_EP, 0x02, DISPLAY_EP_MPS, 0x00),
|
||||
};
|
||||
|
||||
static const uint8_t device_quality_descriptor[] = {
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
};
|
||||
|
||||
static const char *string_descriptors[] = {
|
||||
(const char[]){ 0x09, 0x04 }, /* Langid */
|
||||
"CherryUSB", /* Manufacturer */
|
||||
"cherryusb_R640x480_Ergb16_Fps30_Bl128", /* Product */
|
||||
// "cherryusb_R640x480_Ejpg9_Fps30_Bl128", /* Product */
|
||||
"2022123456", /* Serial Number */
|
||||
};
|
||||
|
||||
static const uint8_t *device_descriptor_callback(uint8_t speed)
|
||||
{
|
||||
return device_descriptor;
|
||||
}
|
||||
|
||||
static const uint8_t *config_descriptor_callback(uint8_t speed)
|
||||
{
|
||||
return config_descriptor;
|
||||
}
|
||||
|
||||
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
|
||||
{
|
||||
return device_quality_descriptor;
|
||||
}
|
||||
|
||||
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
|
||||
{
|
||||
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return string_descriptors[index];
|
||||
}
|
||||
|
||||
const struct usb_descriptor usbdisplay_descriptor = {
|
||||
.device_descriptor_callback = device_descriptor_callback,
|
||||
.config_descriptor_callback = config_descriptor_callback,
|
||||
.device_quality_descriptor_callback = device_quality_descriptor_callback,
|
||||
.string_descriptor_callback = string_descriptor_callback
|
||||
};
|
||||
|
||||
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:
|
||||
break;
|
||||
case USBD_EVENT_SET_REMOTE_WAKEUP:
|
||||
break;
|
||||
case USBD_EVENT_CLR_REMOTE_WAKEUP:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct usbd_interface intf0;
|
||||
|
||||
struct usbd_display_frame frame_pool[2];
|
||||
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t usb_display_buffer[2][640 * 480 * 2];
|
||||
|
||||
void usbdisplay_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
frame_pool[0].frame_buf = usb_display_buffer[0];
|
||||
frame_pool[0].frame_bufsize = 640 * 480 * 2;
|
||||
frame_pool[1].frame_buf = usb_display_buffer[1];
|
||||
frame_pool[1].frame_bufsize = 640 * 480 * 2;
|
||||
|
||||
usbd_desc_register(busid, &usbdisplay_descriptor);
|
||||
|
||||
usbd_add_interface(busid, usbd_display_init_intf(&intf0, DISPLAY_OUT_EP, DISPLAY_IN_EP, frame_pool, 2));
|
||||
usbd_initialize(busid, reg_base, usbd_event_handler);
|
||||
}
|
||||
|
||||
void usbdisplay_poll(void)
|
||||
{
|
||||
struct usbd_display_frame *frame;
|
||||
int ret;
|
||||
|
||||
ret = usbd_display_dequeue(&frame, 0xffffffff); // timeout is not useful for baremental
|
||||
if (ret < 0) {
|
||||
return;
|
||||
}
|
||||
USB_LOG_INFO("frame type: %u, frame size %u\r\n", frame->frame_format, frame->frame_size);
|
||||
usbd_display_enqueue(frame);
|
||||
}
|
||||
@@ -5,16 +5,15 @@
|
||||
# from the environment for the first two.
|
||||
SPHINXOPTS ?=
|
||||
SPHINXBUILD ?= sphinx-build
|
||||
SOURCEDIR = source
|
||||
BUILDDIR = build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
@$(SPHINXBUILD) -M help
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
@$(SPHINXBUILD) -M html "zh" "output/zh" $(SPHINXOPTS) $(O)
|
||||
@$(SPHINXBUILD) -M html "en" "output/en" $(SPHINXOPTS) $(O)
|
||||
|
||||
@@ -16,7 +16,7 @@ build:
|
||||
|
||||
# Build documentation in the "docs/" directory with Sphinx
|
||||
sphinx:
|
||||
configuration: docs/source/conf.py
|
||||
configuration: docs/en/conf.py
|
||||
# You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
|
||||
# builder: "dirhtml"
|
||||
# Fail on all warnings to avoid broken references
|
||||
162
docs/en/api/api_config.rst
Executable file
@@ -0,0 +1,162 @@
|
||||
USB CONFIG Description
|
||||
=======================================
|
||||
|
||||
General CONFIG
|
||||
---------------------
|
||||
|
||||
CONFIG_USB_PRINTF
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
USB log functionality, defaults to redirect to printf. Note that USB log will be used in interrupts, so the redirected API must not block. For example, if using RT-Thread, please change to rt-kprintf
|
||||
|
||||
CONFIG_USB_DBG_LEVEL
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Controls the log print level
|
||||
|
||||
CONFIG_USB_PRINTF_COLOR_ENABLE
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Controls log color printing, enabled by default
|
||||
|
||||
CONFIG_USB_DCACHE_ENABLE
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When not using nocache RAM, enable this macro to ensure data consistency. **When using EHCI, nocache RAM is still required internally**.
|
||||
|
||||
CONFIG_USB_ALIGN_SIZE
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
USB buffer alignment size, default is 4. IP in DMA mode may have alignment requirements for input buffers, typically 4. If other alignment is needed, please modify this value.
|
||||
|
||||
USB_NOCACHE_RAM_SECTION
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If the chip doesn't have cache functionality, this macro is ineffective. If it does, USB input/output buffers must be placed in nocache RAM to ensure data consistency.
|
||||
|
||||
Device Protocol Stack CONFIG
|
||||
------------------------------
|
||||
|
||||
CONFIG_USBDEV_REQUEST_BUFFER_LEN
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Controls the maximum length of control transfer receive and send buffer, default is 512.
|
||||
|
||||
CONFIG_USBDEV_SETUP_LOG_PRINT
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Enable or disable setup packet dump information, disabled by default.
|
||||
|
||||
CONFIG_USBDEV_DESC_CHECK
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Not implemented yet
|
||||
|
||||
CONFIG_USBDEV_TEST_MODE
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Enable or disable USB test mode
|
||||
|
||||
CONFIG_USBDEV_MSC_MAX_BUFSIZE
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Maximum length of MSC cache. Larger cache results in higher USB speed because storage media typically has much higher multi-block read/write speeds than single block, such as SD cards.
|
||||
Default 512. For flash, needs to be changed to 4K. Cache size must be a multiple of the storage media's block size.
|
||||
|
||||
CONFIG_USBDEV_MSC_MANUFACTURER_STRING
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
CONFIG_USBDEV_MSC_PRODUCT_STRING
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
CONFIG_USBDEV_MSC_VERSION_STRING
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
CONFIG_USBDEV_MSC_POLLING
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Run usbd_msc_sector_read and usbd_msc_sector_write operations in while1, used in bare-metal systems.
|
||||
|
||||
CONFIG_USBDEV_MSC_THREAD
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Enable or disable MSC thread, disabled by default. usbd_msc_sector_read and usbd_msc_sector_write are executed in interrupts by default, so if OS is enabled, it's recommended to enable this macro, then usbd_msc_sector_read and usbd_msc_sector_write will execute in threads.
|
||||
|
||||
CONFIG_USBDEV_MSC_PRIO
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Priority of MSC read/write thread, default is 4. Lower values mean higher priority.
|
||||
|
||||
CONFIG_USBDEV_MSC_STACKSIZE
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Stack size of MSC read/write thread, default 2K bytes
|
||||
|
||||
CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Maximum receive and send length for RNDIS control transfers. Minimum length determined by RNDIS options list, default should be greater than or equal to 156.
|
||||
|
||||
CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Maximum length of RNDIS Ethernet frame, default 1580
|
||||
|
||||
CONFIG_USBDEV_RNDIS_VENDOR_ID
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
CONFIG_USBDEV_RNDIS_VENDOR_DESC
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
CONFIG_USBDEV_RNDIS_USING_LWIP
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
RNDIS interface with LWIP
|
||||
|
||||
Host Protocol Stack CONFIG
|
||||
----------------------------
|
||||
|
||||
The following parameters determine the maximum number of supported external hubs, interfaces, endpoints per interface, and altsetting counts. Changing these values affects RAM size, it's recommended to adjust according to actual requirements.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
#define CONFIG_USBHOST_MAX_RHPORTS 1
|
||||
#define CONFIG_USBHOST_MAX_EXTHUBS 1
|
||||
#define CONFIG_USBHOST_MAX_EHPORTS 4
|
||||
#define CONFIG_USBHOST_MAX_INTERFACES 6
|
||||
#define CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 1
|
||||
#define CONFIG_USBHOST_MAX_ENDPOINTS 4
|
||||
|
||||
The following parameters determine the maximum number of supported class drivers. Changing these values affects RAM size, it's recommended to adjust according to actual requirements.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
#define CONFIG_USBHOST_MAX_SERIAL_CLASS 4
|
||||
#define CONFIG_USBHOST_MAX_HID_CLASS 4
|
||||
#define CONFIG_USBHOST_MAX_MSC_CLASS 2
|
||||
#define CONFIG_USBHOST_MAX_AUDIO_CLASS 1
|
||||
#define CONFIG_USBHOST_MAX_VIDEO_CLASS 1
|
||||
|
||||
CONFIG_USBHOST_PSC_PRIO
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Priority of host plug/unplug thread, default is 0. Lower values mean higher priority.
|
||||
|
||||
CONFIG_USBHOST_PSC_STACKSIZE
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Stack size of host plug/unplug thread, default 2K bytes
|
||||
|
||||
CONFIG_USBHOST_REQUEST_BUFFER_LEN
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Maximum length for control transfer receive or send
|
||||
|
||||
CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Timeout for control transfer send or receive, default 500 ms
|
||||
|
||||
CONFIG_USBHOST_MSC_TIMEOUT
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Timeout for MSC read/write transfers, default 5s
|
||||
503
docs/en/api/api_device.rst
Executable file
@@ -0,0 +1,503 @@
|
||||
Device Protocol Stack
|
||||
=======================================
|
||||
|
||||
The device protocol stack is mainly responsible for enumeration and driver loading. We won't discuss enumeration here, but for driver loading (i.e., interface driver loading), it mainly relies on the `usbd_add_interface` function to record the passed-in interface driver and save it to the interface array table. When the host makes class requests, it can search the interface table for access.
|
||||
After calling `usbd_desc_register`, interface registration and endpoint registration need to be performed according to the following rules:
|
||||
|
||||
- Call `usbd_add_interface` as many times as there are interfaces, with parameters filling in the relevant `xxx_init_intf`. If not supported, manually create an intf and fill it in
|
||||
- Call `usbd_add_endpoint` as many times as there are endpoints. When interrupts complete, the registered endpoint callback will be called.
|
||||
|
||||
Refer to the diagram below:
|
||||
|
||||
.. figure:: img/api_device1.png
|
||||
|
||||
CORE
|
||||
-----------------
|
||||
|
||||
Endpoint Structure
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
The endpoint structure is mainly used to register interrupt completion callback functions for different endpoint addresses.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
struct usbd_endpoint {
|
||||
uint8_t ep_addr;
|
||||
usbd_endpoint_callback ep_cb;
|
||||
};
|
||||
|
||||
- **ep_addr** Endpoint address (with direction)
|
||||
- **ep_cb** Endpoint completion interrupt callback function.
|
||||
|
||||
.. note:: To summarize in one sentence: in callback function is equivalent to DMA transmission completion interrupt callback function; out callback function is equivalent to DMA reception completion interrupt callback function
|
||||
|
||||
Interface Structure
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
The interface structure is mainly used to register requests other than standard device requests for different class devices, including class device requests, vendor device requests, and custom device requests, as well as related notification callback functions in the protocol stack.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
struct usbd_interface {
|
||||
usbd_request_handler class_interface_handler;
|
||||
usbd_request_handler class_endpoint_handler;
|
||||
usbd_request_handler vendor_handler;
|
||||
usbd_notify_handler notify_handler;
|
||||
const uint8_t *hid_report_descriptor;
|
||||
uint32_t hid_report_descriptor_len;
|
||||
uint8_t intf_num;
|
||||
};
|
||||
|
||||
- **class_interface_handler** class setup request callback function, recipient is interface
|
||||
- **class_endpoint_handler** class setup request callback function, recipient is endpoint
|
||||
- **vendor_handler** vendor setup request callback function
|
||||
- **notify_handler** interrupt flag, protocol stack related status callback function
|
||||
- **hid_report_descriptor** hid report descriptor
|
||||
- **hid_report_descriptor_len** hid report descriptor length
|
||||
- **intf_num** current interface offset
|
||||
|
||||
usbd_desc_register
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_desc_register`` is used to register USB descriptors. Descriptor types include: device descriptor, configuration descriptor (including configuration descriptor, interface descriptor, class descriptor, endpoint descriptor), string descriptor, device qualifier descriptor, other speed descriptor, BOS descriptor, WinUSB descriptor.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
// Enable CONFIG_USBDEV_ADVANCE_DESC
|
||||
void usbd_desc_register(uint8_t busid, const struct usb_descriptor *desc);
|
||||
|
||||
// Disable CONFIG_USBDEV_ADVANCE_DESC
|
||||
void usbd_desc_register(uint8_t busid, const uint8_t *desc);
|
||||
void usbd_msosv1_desc_register(uint8_t busid, struct usb_msosv1_descriptor *desc);
|
||||
void usbd_msosv2_desc_register(uint8_t busid, struct usb_msosv2_descriptor *desc);
|
||||
void usbd_bos_desc_register(uint8_t busid, struct usb_bos_descriptor *desc);
|
||||
void usbd_webusb_desc_register(uint8_t busid, struct usb_webusb_descriptor *desc);
|
||||
|
||||
- **desc** Descriptor handle
|
||||
|
||||
.. note:: Currently CONFIG_USBDEV_ADVANCE_DESC is enabled by default. If you need to use the old version API, please disable this macro. Starting from v1.6.0, only APIs with CONFIG_USBDEV_ADVANCE_DESC enabled are available
|
||||
|
||||
usbd_add_interface
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_add_interface`` adds an interface driver. **The addition order must follow the interface order in the descriptor**.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_add_interface(uint8_t busid, struct usbd_interface *intf);
|
||||
|
||||
- **busid** USB bus ID
|
||||
- **intf** Interface driver handle, usually obtained from different class `xxx_init_intf` functions
|
||||
|
||||
usbd_add_endpoint
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_add_endpoint`` adds an endpoint interrupt completion callback function.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_add_endpoint(uint8_t busid, struct usbd_endpoint *ep);
|
||||
|
||||
- **busid** USB bus ID
|
||||
- **ep** Endpoint handle
|
||||
|
||||
usbd_initialize
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_initialize`` is used to initialize USB device register configuration, USB clock, interrupts, etc. Note that this function must be called last after registering descriptor APIs. **If using an OS, it must be executed within a thread**.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbd_initialize(uint8_t busid, uintptr_t reg_base, usbd_event_handler_t event_handler);
|
||||
|
||||
- **busid** USB bus ID
|
||||
- **reg_base** USB device register base address
|
||||
- **event_handler** Protocol stack interrupt or status callback function, event events
|
||||
- **return** Returns 0 for success, other values indicate failure
|
||||
|
||||
Event events include:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
USBD_EVENT_ERROR, /** USB error reported by the controller */
|
||||
USBD_EVENT_RESET, /** USB reset */
|
||||
USBD_EVENT_SOF, /** Start of Frame received */
|
||||
USBD_EVENT_CONNECTED, /** USB connected*/
|
||||
USBD_EVENT_DISCONNECTED, /** USB disconnected */
|
||||
USBD_EVENT_SUSPEND, /** USB connection suspended by the HOST */
|
||||
USBD_EVENT_RESUME, /** USB connection resumed by the HOST */
|
||||
|
||||
/* USB DEVICE STATUS */
|
||||
USBD_EVENT_CONFIGURED, /** USB configuration done */
|
||||
USBD_EVENT_SET_INTERFACE, /** USB interface selected */
|
||||
USBD_EVENT_SET_REMOTE_WAKEUP, /** USB set remote wakeup */
|
||||
USBD_EVENT_CLR_REMOTE_WAKEUP, /** USB clear remote wakeup */
|
||||
USBD_EVENT_INIT, /** USB init done when call usbd_initialize */
|
||||
USBD_EVENT_DEINIT, /** USB deinit done when call usbd_deinitialize */
|
||||
USBD_EVENT_UNKNOWN
|
||||
|
||||
.. note:: Most IPs do not support USBD_EVENT_CONNECTED and USBD_EVENT_DISCONNECTED events. Currently only HPM chips support them. For other chips, design your own VBUS detection circuit as an alternative
|
||||
|
||||
usbd_deinitialize
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_deinitialize`` is used to deinitialize USB device, turn off USB device clock, interrupts, etc.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbd_deinitialize(uint8_t busid);
|
||||
|
||||
- **busid** USB bus ID
|
||||
- **return** Returns 0 for success, other values indicate failure
|
||||
|
||||
CDC ACM
|
||||
-----------------
|
||||
|
||||
usbd_cdc_acm_init_intf
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_cdc_acm_init_intf`` is used to initialize USB CDC ACM class interface and implement related functions for this interface.
|
||||
|
||||
- ``cdc_acm_class_interface_request_handler`` is used to handle USB CDC ACM class Setup requests.
|
||||
- ``cdc_notify_handler`` is used to handle other USB CDC interrupt callback functions.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
struct usbd_interface *usbd_cdc_acm_init_intf(uint8_t busid, struct usbd_interface *intf);
|
||||
|
||||
- **busid** USB bus ID
|
||||
- **return** Interface handle
|
||||
|
||||
usbd_cdc_acm_set_line_coding
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_cdc_acm_set_line_coding`` is used to configure the serial port. If only using USB without serial port, this interface does not need to be implemented by the user and can use the default.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_cdc_acm_set_line_coding(uint8_t busid, uint8_t intf, struct cdc_line_coding *line_coding);
|
||||
|
||||
- **busid** USB bus ID
|
||||
- **intf** Control interface number
|
||||
- **line_coding** Serial port configuration
|
||||
|
||||
usbd_cdc_acm_get_line_coding
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_cdc_acm_get_line_coding`` is used to get serial port configuration. If only using USB without serial port, this interface does not need to be implemented by the user and can use the default.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_cdc_acm_get_line_coding(uint8_t busid, uint8_t intf, struct cdc_line_coding *line_coding);
|
||||
|
||||
- **busid** USB bus ID
|
||||
- **intf** Control interface number
|
||||
- **line_coding** Serial port configuration
|
||||
|
||||
usbd_cdc_acm_set_dtr
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_cdc_acm_set_dtr`` is used to control serial port DTR. If only using USB without serial port, this interface does not need to be implemented by the user and can use the default.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_cdc_acm_set_dtr(uint8_t busid, uint8_t intf, bool dtr);
|
||||
|
||||
- **busid** USB bus ID
|
||||
- **intf** Control interface number
|
||||
- **dtr** dtr = 1 means pull low level, 0 means pull high level
|
||||
|
||||
usbd_cdc_acm_set_rts
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_cdc_acm_set_rts`` is used to control serial port RTS. If only using USB without serial port, this interface does not need to be implemented by the user and can use the default.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_cdc_acm_set_rts(uint8_t busid, uint8_t intf, bool rts);
|
||||
|
||||
- **busid** USB bus ID
|
||||
- **intf** Control interface number
|
||||
- **rts** rts = 1 means pull low level, 0 means pull high level
|
||||
|
||||
CDC_ACM_DESCRIPTOR_INIT
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``CDC_ACM_DESCRIPTOR_INIT`` configures the default CDC ACM required descriptors and parameters for user convenience. Total length is `CDC_ACM_DESCRIPTOR_LEN`.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
CDC_ACM_DESCRIPTOR_INIT(bFirstInterface, int_ep, out_ep, in_ep, str_idx);
|
||||
|
||||
- **bFirstInterface** Indicates the offset of the first interface of this CDC ACM in all interfaces
|
||||
- **int_ep** Indicates interrupt endpoint address (with direction)
|
||||
- **out_ep** Indicates bulk out endpoint address (with direction)
|
||||
- **in_ep** Indicates bulk in endpoint address (with direction)
|
||||
- **str_idx** String ID corresponding to control interface
|
||||
|
||||
HID
|
||||
-----------------
|
||||
|
||||
usbd_hid_init_intf
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_hid_init_intf`` is used to initialize USB HID class interface and implement related functions for this interface:
|
||||
|
||||
- ``hid_class_interface_request_handler`` is used to handle USB HID class Setup requests.
|
||||
- ``hid_notify_handler`` is used to handle other USB HID interrupt callback functions.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
struct usbd_interface *usbd_hid_init_intf(uint8_t busid, struct usbd_interface *intf, const uint8_t *desc, uint32_t desc_len);
|
||||
|
||||
- **busid** USB bus ID
|
||||
- **desc** Report descriptor
|
||||
- **desc_len** Report descriptor length
|
||||
|
||||
MSC
|
||||
-----------------
|
||||
|
||||
usbd_msc_init_intf
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
``usbd_msc_init_intf`` is used to initialize MSC class interface, implement related functions for this interface, and register endpoint callback functions. (Since MSC BOT protocol is fixed, user implementation is not needed, so endpoint callback functions naturally don't need user implementation).
|
||||
|
||||
- ``msc_storage_class_interface_request_handler`` is used to handle USB MSC Setup interrupt requests.
|
||||
- ``msc_storage_notify_handler`` is used to implement other USB MSC interrupt callback functions.
|
||||
|
||||
- ``mass_storage_bulk_out`` is used to handle USB MSC endpoint out interrupts.
|
||||
- ``mass_storage_bulk_in`` is used to handle USB MSC endpoint in interrupts.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
struct usbd_interface *usbd_msc_init_intf(uint8_t busid, struct usbd_interface *intf, const uint8_t out_ep, const uint8_t in_ep);
|
||||
|
||||
- **busid** USB bus ID
|
||||
- **out_ep** out endpoint address
|
||||
- **in_ep** in endpoint address
|
||||
|
||||
usbd_msc_get_cap
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_msc_get_cap`` is used to get the LUN, number of sectors, and sector size of the storage device. Users must implement this function.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_msc_get_cap(uint8_t busid, uint8_t lun, uint32_t *block_num, uint16_t *block_size);
|
||||
|
||||
- **busid** USB bus ID
|
||||
- **lun** Storage logical unit, currently unused, defaults to supporting one
|
||||
- **block_num** Number of storage sectors
|
||||
- **block_size** Storage sector size
|
||||
|
||||
usbd_msc_sector_read
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_msc_sector_read`` is used to read data from a storage device starting at a specific sector address. Users must implement this function.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbd_msc_sector_read(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length);
|
||||
|
||||
- **busid** USB bus ID
|
||||
- **lun** Storage logical unit, currently unused, defaults to supporting one
|
||||
- **sector** Sector offset
|
||||
- **buffer** Pointer to store read data
|
||||
- **length** Read length
|
||||
|
||||
|
||||
usbd_msc_sector_write
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_msc_sector_write`` is used to write data to a storage device starting at a specific sector. Users must implement this function.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbd_msc_sector_write(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length);
|
||||
|
||||
- **busid** USB bus ID
|
||||
- **lun** Storage logical unit, currently unused, defaults to supporting one
|
||||
- **sector** Sector offset
|
||||
- **buffer** Write data pointer
|
||||
- **length** Write length
|
||||
|
||||
UAC
|
||||
-----------------
|
||||
|
||||
usbd_audio_init_intf
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_audio_init_intf`` is used to initialize USB Audio class interface and implement related functions for this interface:
|
||||
|
||||
- ``audio_class_interface_request_handler`` is used to handle USB Audio Setup interface recipient interrupt requests.
|
||||
- ``audio_class_endpoint_request_handler`` is used to handle USB Audio Setup endpoint recipient interrupt requests.
|
||||
- ``audio_notify_handler`` is used to implement other USB Audio interrupt callback functions.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
struct usbd_interface *usbd_audio_init_intf(uint8_t busid, struct usbd_interface *intf,
|
||||
uint16_t uac_version,
|
||||
struct audio_entity_info *table,
|
||||
uint8_t num);
|
||||
|
||||
- **busid** USB bus ID
|
||||
- **intf** Interface handle
|
||||
- **uac_version** Audio class version, UAC1.0 or UAC2.0
|
||||
- **table** Audio entity information table
|
||||
- **num** Audio entity information table length
|
||||
|
||||
usbd_audio_open
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_audio_open`` is used to start audio data transmission. Host sends start command callback function.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_audio_open(uint8_t intf);
|
||||
|
||||
- **intf** Interface number to open
|
||||
|
||||
usbd_audio_close
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_audio_close`` is used to stop audio data transmission. Host sends stop command callback function.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_audio_close(uint8_t intf);
|
||||
|
||||
- **intf** Interface number to close
|
||||
|
||||
usbd_audio_set_mute
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_audio_set_mute`` is used to set mute.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_audio_set_mute(uint8_t busid, uint8_t ep, uint8_t ch, bool mute);
|
||||
|
||||
- **busid** USB bus ID
|
||||
- **ep** Endpoint to set mute
|
||||
- **ch** Channel to set mute
|
||||
- **mute** 1 means mute, 0 means opposite
|
||||
|
||||
usbd_audio_set_volume
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_audio_set_volume`` is used to set volume.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_audio_set_volume(uint8_t busid, uint8_t ep, uint8_t ch, int volume_db);
|
||||
|
||||
- **busid** USB bus ID
|
||||
- **ep** Endpoint to set volume
|
||||
- **ch** Channel to set volume
|
||||
- **volume_db** Volume to set in decibels, range -100dB ~ 0dB
|
||||
|
||||
usbd_audio_set_sampling_freq
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_audio_set_sampling_freq`` is used to set the sampling rate of the audio module on the device
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_audio_set_sampling_freq(uint8_t busid, uint8_t ep, uint32_t sampling_freq);
|
||||
|
||||
- **ep** Endpoint to set sampling rate
|
||||
- **sampling_freq** Sampling rate to set
|
||||
|
||||
usbd_audio_get_sampling_freq_table
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_audio_get_sampling_freq_table`` is used to get the list of supported sampling rates. If the function is not implemented, the default sampling rate list is used. UAC2 only.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_audio_get_sampling_freq_table(uint8_t busid, uint8_t ep, uint8_t **sampling_freq_table);
|
||||
|
||||
- **ep** Endpoint to get sampling rate
|
||||
- **sampling_freq_table** Sampling rate list address, format refers to default sampling rate list
|
||||
|
||||
UVC
|
||||
-----------------
|
||||
|
||||
usbd_video_init_intf
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_video_init_intf`` is used to initialize USB Video class interface and implement related functions for this interface:
|
||||
|
||||
- ``video_class_interface_request_handler`` is used to handle USB Video Setup interrupt requests.
|
||||
- ``video_notify_handler`` is used to implement other USB Video interrupt callback functions.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
struct usbd_interface *usbd_video_init_intf(uint8_t busid, struct usbd_interface *intf,
|
||||
uint32_t dwFrameInterval,
|
||||
uint32_t dwMaxVideoFrameSize,
|
||||
uint32_t dwMaxPayloadTransferSize);
|
||||
- **busid** USB bus ID
|
||||
- **intf** Interface handle
|
||||
- **dwFrameInterval** Video frame interval, unit 100ns
|
||||
- **dwMaxVideoFrameSize** Maximum video frame size
|
||||
- **dwMaxPayloadTransferSize** Maximum payload transfer size
|
||||
|
||||
usbd_video_open
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_video_open`` is used to start video data transmission.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_video_open(uint8_t intf);
|
||||
|
||||
- **intf** Interface number to open
|
||||
|
||||
usbd_video_close
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_video_close`` is used to stop video data transmission.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_video_open(uint8_t intf);
|
||||
|
||||
- **intf** Interface number to close
|
||||
|
||||
usbd_video_stream_start_write
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_video_stream_start_write`` is used to start sending one frame of video data stream. Must be used together with `usbd_video_stream_split_transfer`.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbd_video_stream_start_write(uint8_t busid, uint8_t ep, uint8_t *ep_buf, uint8_t *stream_buf, uint32_t stream_len, bool do_copy);
|
||||
|
||||
- **busid** USB bus ID
|
||||
- **ep** Video data endpoint address
|
||||
- **ep_buf** Video data endpoint transfer buffer
|
||||
- **stream_buf** One frame video data source buffer
|
||||
- **stream_len** One frame video data source buffer size
|
||||
- **do_copy** Whether to copy stream_buf data to ep_buf. This parameter is false only when stream_buf is in nocache area and DCACHE_ENABLE is not enabled
|
||||
|
||||
usbd_video_stream_split_transfer
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_video_stream_split_transfer`` is used to split video data stream transmission. Must be used together with `usbd_video_stream_start_write`.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbd_video_stream_split_transfer(uint8_t busid, uint8_t ep);
|
||||
|
||||
- **busid** USB bus ID
|
||||
- **ep** Video data endpoint address
|
||||
- **return** Returns true when one frame data transmission is complete, false when data transmission is not complete
|
||||
|
||||
RNDIS
|
||||
-----------------
|
||||
|
||||
CDC ECM
|
||||
-----------------
|
||||
|
||||
MTP
|
||||
-----------------
|
||||
317
docs/en/api/api_host.rst
Executable file
@@ -0,0 +1,317 @@
|
||||
Host Protocol Stack
|
||||
=======================================
|
||||
|
||||
For the naming, classification, and member composition of structures in the host protocol stack, refer to the following two diagrams:
|
||||
|
||||
.. figure:: img/api_host1.png
|
||||
.. figure:: img/api_host2.png
|
||||
|
||||
CORE
|
||||
-----------------
|
||||
|
||||
CLASS Driver Information Structure
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
struct usbh_class_info {
|
||||
uint8_t match_flags; /* Used for product specific matches; range is inclusive */
|
||||
uint8_t bInterfaceClass; /* Base device class code */
|
||||
uint8_t bInterfaceSubClass; /* Sub-class, depends on base class. Eg. */
|
||||
uint8_t bInterfaceProtocol; /* Protocol, depends on base class. Eg. */
|
||||
const uint16_t (*id_table)[2]; /* List of Vendor/Product ID pairs */
|
||||
const struct usbh_class_driver *class_driver;
|
||||
};
|
||||
|
||||
Endpoint Structure
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
struct usbh_endpoint {
|
||||
struct usb_endpoint_descriptor ep_desc;
|
||||
};
|
||||
|
||||
Interface Altsetting Structure
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
struct usbh_interface_altsetting {
|
||||
struct usb_interface_descriptor intf_desc;
|
||||
struct usbh_endpoint ep[CONFIG_USBHOST_MAX_ENDPOINTS];
|
||||
};
|
||||
|
||||
Interface Structure
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
struct usbh_interface {
|
||||
char devname[CONFIG_USBHOST_DEV_NAMELEN];
|
||||
struct usbh_class_driver *class_driver;
|
||||
void *priv;
|
||||
struct usbh_interface_altsetting altsetting[CONFIG_USBHOST_MAX_INTF_ALTSETTINGS];
|
||||
uint8_t altsetting_num;
|
||||
};
|
||||
|
||||
Configuration Structure
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
struct usbh_configuration {
|
||||
struct usb_configuration_descriptor config_desc;
|
||||
struct usbh_interface intf[CONFIG_USBHOST_MAX_INTERFACES];
|
||||
};
|
||||
|
||||
hubport Structure
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
struct usbh_hubport {
|
||||
bool connected; /* True: device connected; false: disconnected */
|
||||
uint8_t port; /* Hub port index */
|
||||
uint8_t dev_addr; /* device address */
|
||||
uint8_t speed; /* device speed */
|
||||
uint8_t depth; /* distance from root hub */
|
||||
uint8_t route; /* route string */
|
||||
uint8_t slot_id; /* slot id */
|
||||
struct usb_device_descriptor device_desc;
|
||||
struct usbh_configuration config;
|
||||
const char *iManufacturer;
|
||||
const char *iProduct;
|
||||
const char *iSerialNumber;
|
||||
uint8_t *raw_config_desc;
|
||||
struct usb_setup_packet *setup;
|
||||
struct usbh_hub *parent;
|
||||
struct usbh_hub *self; /* if this hubport is a hub */
|
||||
struct usbh_bus *bus;
|
||||
struct usb_endpoint_descriptor ep0;
|
||||
struct usbh_urb ep0_urb;
|
||||
usb_osal_mutex_t mutex;
|
||||
};
|
||||
|
||||
hub Structure
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
struct usbh_hub {
|
||||
bool connected;
|
||||
bool is_roothub;
|
||||
uint8_t index;
|
||||
uint8_t hub_addr;
|
||||
uint8_t speed;
|
||||
uint8_t nports;
|
||||
uint8_t powerdelay;
|
||||
uint8_t tt_think;
|
||||
bool ismtt;
|
||||
struct usb_hub_descriptor hub_desc; /* USB 2.0 only */
|
||||
struct usb_hub_ss_descriptor hub_ss_desc; /* USB 3.0 only */
|
||||
struct usbh_hubport child[CONFIG_USBHOST_MAX_EHPORTS];
|
||||
struct usbh_hubport *parent;
|
||||
struct usbh_bus *bus;
|
||||
struct usb_endpoint_descriptor *intin;
|
||||
struct usbh_urb intin_urb;
|
||||
uint8_t *int_buffer;
|
||||
struct usb_osal_timer *int_timer;
|
||||
};
|
||||
|
||||
usbh_initialize
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbh_initialize`` is used to initialize the USB host protocol stack, including: initializing the USB host controller, creating roothub device, creating hub detection thread.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbh_initialize(uint8_t busid, uint32_t reg_base, usbh_event_handler_t event_handler);
|
||||
|
||||
- **busid** bus id, starting from 0, cannot exceed `CONFIG_USBHOST_MAX_BUS`
|
||||
- **reg_base** hcd register base address
|
||||
- **event_handler** host event callback function, can be NULL
|
||||
- **return** 0 indicates normal, other values indicate error
|
||||
|
||||
usbh_find_class_instance
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbh_find_class_instance`` finds the corresponding class structure handle based on the registered class name.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void *usbh_find_class_instance(const char *devname);
|
||||
|
||||
- **devname** class name
|
||||
- **return** class structure handle
|
||||
|
||||
lsusb
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``lsusb`` is used to view and operate device information on the hub. Requires shell plugin to use.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int lsusb(int argc, char **argv);
|
||||
|
||||
SERIAL
|
||||
-----------------
|
||||
|
||||
usbh_serial_open
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbh_serial_open`` opens a serial device according to the path.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
struct usbh_serial *usbh_serial_open(const char *devname, uint32_t open_flags);
|
||||
|
||||
- **devname** serial path
|
||||
- **open_flags** open flags, refer to `USBH_SERIAL_OFLAG_*` definitions
|
||||
- **return** serial structure handle
|
||||
|
||||
usbh_serial_close
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbh_serial_close`` closes the serial device.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbh_serial_close(struct usbh_serial *serial);
|
||||
|
||||
- **serial** serial structure handle
|
||||
|
||||
usbh_serial_control
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbh_serial_control`` configures the serial port.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbh_serial_control(struct usbh_serial *serial, int cmd, void *arg);
|
||||
|
||||
- **serial** serial structure handle
|
||||
- **cmd** control command, refer to `USBH_SERIAL_CMD_*` definitions
|
||||
- **arg** control parameter pointer
|
||||
- **return** 0 indicates normal, other values indicate error
|
||||
|
||||
usbh_serial_write
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbh_serial_write`` writes data to the serial port.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbh_serial_write(struct usbh_serial *serial, const void *buffer, uint32_t buflen);
|
||||
|
||||
- **serial** serial structure handle
|
||||
- **buffer** data buffer pointer
|
||||
- **buflen** length of data to write
|
||||
- **return** actual length of data written or error code
|
||||
|
||||
.. note:: If CONFIG_USB_DCACHE_ENABLE is not enabled, buffer needs to be in nocache area, otherwise it needs to be aligned to CONFIG_USB_ALIGN_SIZE area.
|
||||
|
||||
usbh_serial_read
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbh_serial_read`` reads data from the serial port. **If baud rate is not set, this API is not allowed to be used. After setting baud rate, rx reception will be enabled internally and data will be written to ringbuf**.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbh_serial_read(struct usbh_serial *serial, void *buffer, uint32_t buflen);
|
||||
|
||||
- **serial** serial structure handle
|
||||
- **buffer** data buffer pointer
|
||||
- **buflen** maximum length of data to read
|
||||
- **return** actual length of data read or error code
|
||||
|
||||
.. note:: Since ringbuffer is used internally, there are no restrictions on user buffer attributes.
|
||||
|
||||
usbh_serial_cdc_write_async
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbh_serial_cdc_write_async`` asynchronously writes data to the serial port. **If baud rate is set, this API is not allowed to be used**.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbh_serial_cdc_write_async(struct usbh_serial *serial, uint8_t *buffer, uint32_t buflen, usbh_complete_callback_t complete, void *arg);
|
||||
|
||||
- **serial** serial structure handle
|
||||
- **buffer** data buffer pointer
|
||||
- **buflen** length of data to send
|
||||
- **complete** data write completion callback function
|
||||
- **arg** callback function parameter
|
||||
- **return** 0 indicates normal, other values indicate error
|
||||
|
||||
.. note:: If CONFIG_USB_DCACHE_ENABLE is not enabled, buffer needs to be in nocache area, otherwise it needs to be aligned to CONFIG_USB_ALIGN_SIZE area.
|
||||
|
||||
usbh_serial_cdc_read_async
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbh_serial_cdc_read_async`` asynchronously reads data from the serial port. **If baud rate is set, this API is not allowed to be used. After setting baud rate, rx reception will be enabled internally and data will be written to ringbuf**.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbh_serial_cdc_read_async(struct usbh_serial *serial, uint8_t *buffer, uint32_t buflen, usbh_complete_callback_t complete, void *arg);
|
||||
|
||||
- **serial** serial structure handle
|
||||
- **buffer** data buffer pointer
|
||||
- **buflen** maximum length of data to read, up to 16K at a time. Must be a multiple of wMaxPacketSize
|
||||
- **complete** data read completion callback function
|
||||
- **arg** callback function parameter
|
||||
- **return** 0 indicates normal, other values indicate error
|
||||
|
||||
.. note:: If CONFIG_USB_DCACHE_ENABLE is not enabled, buffer needs to be in nocache area, otherwise it needs to be aligned to CONFIG_USB_ALIGN_SIZE area.
|
||||
|
||||
HID
|
||||
-----------------
|
||||
|
||||
MSC
|
||||
-----------------
|
||||
|
||||
usbh_msc_scsi_init
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbh_msc_scsi_init`` initializes msc scsi device. Gets MSC status and capacity information.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbh_msc_scsi_init(struct usbh_msc *msc_class);
|
||||
|
||||
- **msc_class** msc structure handle
|
||||
- **return** 0 indicates normal, other values indicate error
|
||||
|
||||
usbh_msc_scsi_write10
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbh_msc_scsi_write10`` writes data to msc device.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbh_msc_scsi_write10(struct usbh_msc *msc_class, uint32_t start_sector, const uint8_t *buffer, uint32_t nsectors);
|
||||
|
||||
- **msc_class** msc structure handle
|
||||
- **start_sector** starting sector
|
||||
- **buffer** data buffer pointer
|
||||
- **nsectors** number of sectors to write
|
||||
- **return** returns 0 for normal, other values indicate error
|
||||
|
||||
usbh_msc_scsi_read10
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbh_msc_scsi_read10`` reads data from msc device.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbh_msc_scsi_read10(struct usbh_msc *msc_class, uint32_t start_sector, uint8_t *buffer, uint32_t nsectors);
|
||||
|
||||
- **msc_class** msc structure handle
|
||||
- **start_sector** starting sector
|
||||
- **buffer** data buffer pointer
|
||||
- **nsectors** number of sectors to read
|
||||
- **return** returns 0 for normal, other values indicate error
|
||||
|
||||
NETWORK
|
||||
-----------------
|
||||
|
||||
Already integrated with lwIP protocol stack or other network protocol stacks, use socket API.
|
||||
266
docs/en/api/api_port.rst
Executable file
@@ -0,0 +1,266 @@
|
||||
Host and Device Drivers
|
||||
=======================================
|
||||
|
||||
.. note:: Please note that starting from version v1.1, the busid parameter has been added, while everything else remains unchanged, so API documentation is not updated
|
||||
|
||||
device controller(dcd)
|
||||
-------------------------
|
||||
|
||||
usb_dc_init
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usb_dc_init`` is used to initialize USB device controller registers, set USB pins, clock, interrupts, etc. **This function is not open to users**.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usb_dc_init(void);
|
||||
|
||||
- **return** Returns 0 for success, other values indicate error
|
||||
|
||||
usb_dc_deinit
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usb_dc_deinit`` is used to de-initialize USB device controller registers. **This function is not open to users**.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usb_dc_deinit(void);
|
||||
|
||||
- **return** Returns 0 for success, other values indicate error
|
||||
|
||||
usbd_set_address
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_set_address`` sets the device address. **This function is not open to users**.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbd_set_address(const uint8_t addr);
|
||||
|
||||
- **addr** Device address
|
||||
- **return** Returns 0 for success, other values indicate error
|
||||
|
||||
usbd_ep_open
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_ep_open`` sets endpoint properties and enables corresponding endpoint interrupts. **This function is not open to users**.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbd_ep_open(const struct usb_endpoint_descriptor *ep);
|
||||
|
||||
- **ep** Endpoint descriptor
|
||||
- **return** Returns 0 for success, other values indicate error
|
||||
|
||||
usbd_ep_close
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_ep_close`` closes an endpoint. **This function is not open to users**.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbd_ep_close(const uint8_t ep);
|
||||
|
||||
- **ep** Endpoint address
|
||||
- **return** Returns 0 for success, other values indicate error
|
||||
|
||||
usbd_ep_set_stall
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_ep_set_stall`` sets an endpoint to stall state and sends a stall handshake packet. **This function is open to users**.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbd_ep_set_stall(const uint8_t ep);
|
||||
|
||||
- **ep** Endpoint address
|
||||
- **return** Returns 0 for success, other values indicate error
|
||||
|
||||
usbd_ep_clear_stall
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_ep_clear_stall`` clears the stall state of an endpoint. **This function is not open to users**.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbd_ep_clear_stall(const uint8_t ep);
|
||||
|
||||
- **ep** Endpoint address
|
||||
- **return** Returns 0 for success, other values indicate error
|
||||
|
||||
usbd_ep_is_stalled
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_ep_is_stalled`` reads the current stall state of an endpoint. **This function is not open to users**.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbd_ep_is_stalled(const uint8_t ep, uint8_t *stalled);
|
||||
|
||||
- **ep** Endpoint address
|
||||
- **return** Returns 1 for stalled, 0 for not stalled
|
||||
|
||||
usbd_ep_start_write
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_ep_start_write`` starts endpoint transmission. After transmission completion, it will call the registered IN endpoint transfer completion interrupt callback function. This function performs asynchronous transmission. **This function is open to users**.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbd_ep_start_write(const uint8_t ep, const uint8_t *data, uint32_t data_len);
|
||||
|
||||
- **ep** IN endpoint address
|
||||
- **data** Transmission data buffer
|
||||
- **data_len** Transmission length, theoretically unlimited, recommended within 16K bytes
|
||||
- **return** Returns 0 for success, other values indicate error
|
||||
|
||||
usbd_ep_start_read
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_ep_start_read`` starts endpoint reception. After reception completion, it will call the registered OUT endpoint transfer completion interrupt callback function. This function performs asynchronous reception. **This function is open to users**.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbd_ep_start_read(const uint8_t ep, uint8_t *data, uint32_t data_len);
|
||||
|
||||
- **ep** OUT endpoint address
|
||||
- **data** Reception data buffer
|
||||
- **data_len** Reception length, theoretically unlimited, recommended within 16K bytes, and preferably a multiple of maximum packet size
|
||||
- **return** Returns 0 for success, other values indicate error
|
||||
|
||||
.. note:: After starting reception, transfer completion interrupt will be triggered under two conditions: 1. Last packet is a short packet (less than EP MPS); 2. Total received length equals data_len
|
||||
|
||||
.. note:: For bulk transfers, data_len is usually designed as EP MPS. The following three cases can be modified to multiple EP MPS: fixed length; custom protocol with length information (MSC); host manually sends ZLP or short packet (RNDIS)
|
||||
|
||||
host controller(hcd)
|
||||
------------------------
|
||||
|
||||
usb_hc_init
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usb_hc_init`` is used to initialize USB host controller registers, set USB pins, clock, interrupts, etc. **This function is not open to users**.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usb_hc_init(void);
|
||||
|
||||
- **return** Returns 0 for success, other values indicate error
|
||||
|
||||
usb_hc_deinit
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usb_hc_deinit`` is used to de-initialize USB host controller registers. **This function is not open to users**.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usb_hc_deinit(void);
|
||||
|
||||
- **return** Returns 0 for success, other values indicate error
|
||||
|
||||
usbh_roothub_control
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbh_roothub_control`` is used to send requests to the root hub. **This function is not open to users**.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbh_roothub_control(struct usb_setup_packet *setup, uint8_t *buf);
|
||||
|
||||
- **setup** Request
|
||||
- **buf** Reception buffer
|
||||
- **return** Returns 0 for success, other values indicate error
|
||||
|
||||
usbh_submit_urb
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbh_submit_urb`` performs data requests to endpoints at a specific address. **This function is open to users**.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbh_submit_urb(struct usbh_urb *urb);
|
||||
|
||||
- **urb** USB request block
|
||||
- **return** Returns 0 for success, other values indicate error
|
||||
|
||||
Among them, the `urb` structure information is as follows:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
struct usbh_urb {
|
||||
usb_slist_t list;
|
||||
void *hcpriv;
|
||||
struct usbh_hubport *hport;
|
||||
struct usb_endpoint_descriptor *ep;
|
||||
uint8_t data_toggle;
|
||||
uint8_t interval;
|
||||
struct usb_setup_packet *setup;
|
||||
uint8_t *transfer_buffer;
|
||||
uint32_t transfer_buffer_length;
|
||||
int transfer_flags;
|
||||
uint32_t actual_length;
|
||||
uint32_t timeout;
|
||||
int errorcode;
|
||||
uint32_t num_of_iso_packets;
|
||||
uint32_t start_frame;
|
||||
usbh_complete_callback_t complete;
|
||||
void *arg;
|
||||
#if defined(__ICCARM__) || defined(__ICCRISCV__) || defined(__ICCRX__)
|
||||
struct usbh_iso_frame_packet *iso_packet;
|
||||
#else
|
||||
struct usbh_iso_frame_packet iso_packet[0];
|
||||
#endif
|
||||
};
|
||||
|
||||
- **hcpriv** Host controller driver private member
|
||||
- **hport** The hport used by current URB
|
||||
- **ep** The endpoint used by current URB
|
||||
- **data_toggle** Current data toggle
|
||||
- **interval** URB transfer interval in microseconds. If interval is greater than 1000us, software timer needs to be used for maintenance
|
||||
- **setup** Setup request buffer, used by endpoint 0
|
||||
- **transfer_buffer** Transfer data buffer
|
||||
- **transfer_buffer_length** Transfer length
|
||||
- **transfer_flags** Flags carried during transfer
|
||||
- **actual_length** Actual transfer length
|
||||
- **timeout** Transfer timeout. If 0, the function is non-blocking and can be used in interrupts
|
||||
- **errorcode** Error code
|
||||
- **num_of_iso_packets** Number of ISO frames or microframes
|
||||
- **complete** Transfer completion callback function
|
||||
- **arg** Parameters carried when transfer completes
|
||||
- **iso_packet** ISO data packet
|
||||
|
||||
.. note:: If there are no special time requirements for timeout, it must be set to 0xffffffff. In principle, timeout is not allowed. If timeout occurs, generally cannot continue working
|
||||
|
||||
`errorcode` can return the following values:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
#define USB_ERR_NOMEM 1
|
||||
#define USB_ERR_INVAL 2
|
||||
#define USB_ERR_NODEV 3
|
||||
#define USB_ERR_NOTCONN 4
|
||||
#define USB_ERR_NOTSUPP 5
|
||||
#define USB_ERR_BUSY 6
|
||||
#define USB_ERR_RANGE 7
|
||||
#define USB_ERR_STALL 8
|
||||
#define USB_ERR_BABBLE 9
|
||||
#define USB_ERR_NAK 10
|
||||
#define USB_ERR_DT 11
|
||||
#define USB_ERR_IO 12
|
||||
#define USB_ERR_SHUTDOWN 13
|
||||
#define USB_ERR_TIMEOUT 14
|
||||
|
||||
Among them, the `iso_packet` structure information is as follows:
|
||||
|
||||
.. 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 data buffer
|
||||
- **transfer_buffer_length** Transfer length
|
||||
- **actual_length** Actual transfer length
|
||||
- **errorcode** Error code
|
||||
0
docs/source/api/img/api_device1.png → docs/en/api/img/api_device1.png
Normal file → Executable file
|
Before Width: | Height: | Size: 290 KiB After Width: | Height: | Size: 290 KiB |
0
docs/source/api/img/api_host1.png → docs/en/api/img/api_host1.png
Normal file → Executable file
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
0
docs/source/api/img/api_host2.png → docs/en/api/img/api_host2.png
Normal file → Executable file
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
4
docs/en/class/class_audio.rst
Executable file
@@ -0,0 +1,4 @@
|
||||
UAC
|
||||
=======================================
|
||||
|
||||
Reference official audio-related PDFs
|
||||
4
docs/en/class/class_cdc.rst
Executable file
@@ -0,0 +1,4 @@
|
||||
CDC
|
||||
=======================================
|
||||
|
||||
Reference official CDC-related PDFs
|
||||
4
docs/en/class/class_hid.rst
Executable file
@@ -0,0 +1,4 @@
|
||||
HID
|
||||
=======================================
|
||||
|
||||
Reference official HID-related PDFs
|
||||
4
docs/en/class/class_msc.rst
Executable file
@@ -0,0 +1,4 @@
|
||||
MSC
|
||||
=======================================
|
||||
|
||||
Reference official MSC-related PDFs
|
||||
4
docs/en/class/class_video.rst
Executable file
@@ -0,0 +1,4 @@
|
||||
UVC
|
||||
=======================================
|
||||
|
||||
Reference official video-related PDFs
|
||||
2
docs/en/class/winusb.rst
Executable file
@@ -0,0 +1,2 @@
|
||||
WINUSB
|
||||
=======================================
|
||||
2
docs/source/conf.py → docs/en/conf.py
Normal file → Executable file
@@ -3,7 +3,7 @@
|
||||
# -- Project information
|
||||
|
||||
project = 'CherryUSB'
|
||||
copyright = '2022 ~ 2025, sakumisu'
|
||||
copyright = '2022 ~ 2026, sakumisu'
|
||||
author = 'sakumisu'
|
||||
|
||||
release = '1.6.0'
|
||||
0
docs/source/demo/img/cherryadb.png → docs/en/demo/img/cherryadb.png
Normal file → Executable file
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
0
docs/source/demo/img/otg.png → docs/en/demo/img/otg.png
Normal file → Executable file
|
Before Width: | Height: | Size: 466 KiB After Width: | Height: | Size: 466 KiB |
0
docs/source/demo/img/rtt_adb_shell1.png → docs/en/demo/img/rtt_adb_shell1.png
Normal file → Executable file
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |
0
docs/source/demo/img/rtt_adb_shell2.png → docs/en/demo/img/rtt_adb_shell2.png
Normal file → Executable file
|
Before Width: | Height: | Size: 497 KiB After Width: | Height: | Size: 497 KiB |
0
docs/source/demo/img/usbh_serial.png → docs/en/demo/img/usbh_serial.png
Normal file → Executable file
|
Before Width: | Height: | Size: 3.7 MiB After Width: | Height: | Size: 3.7 MiB |
14
docs/en/demo/usb_otg.rst
Executable file
@@ -0,0 +1,14 @@
|
||||
USB OTG
|
||||
=================
|
||||
|
||||
If you need to use OTG functionality, first the chip you're using needs to support ID detection capability, then enable the ``CONFIG_USB_OTG_ENABLE`` macro, and replace ``usbh_initialize`` or ``usbd_initialize`` in previous examples with ``usbotg_initialize``.
|
||||
|
||||
The ID detection circuit varies depending on different USB interface types, with micro-USB and USB-C being the two common interface types.
|
||||
|
||||
- If it's a micro-USB interface, connect the ID line to the chip's ID pin and enable the ID function.
|
||||
- If it's a USB-C interface, since there's no ID pin, you need to use CC circuit to convert to ID and then connect to the chip's ID pin. A common circuit diagram is shown below (DNP means Do Not Populate):
|
||||
|
||||
.. figure:: img/otg.png
|
||||
|
||||
|
||||
.. note:: In addition to the ID pin, you also need to add VBUS output switch control. When working in host mode, enable VBUS power supply; when working in device mode, disable VBUS power supply.
|
||||
28
docs/en/demo/usbd_adb.rst
Executable file
@@ -0,0 +1,28 @@
|
||||
ADB Device
|
||||
=================
|
||||
|
||||
The adb device demo refers to the `demo/adb/usbd_adb_template.c` template. It adapts to **cherrysh** (`platform/demo/adb/cherrysh_port.c`) and **rt-thread msh** (`platform/rtthread/usbd_adb_shell.c`) by default. You only need to add the following initialization in main.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
cherryadb_init(0, xxxxx);
|
||||
|
||||
If using rt-thread, you also need to enable adb device in menuconfig.
|
||||
|
||||
.. figure:: img/rtt_adb_shell1.png
|
||||
|
||||
Entering ADB
|
||||
--------------
|
||||
|
||||
- When using **cherrysh**, automatically enters adb mode after enumeration is completed
|
||||
- When using **msh**, you need to input ``adb_enter`` in **msh** to enter adb mode
|
||||
|
||||
Exiting ADB
|
||||
--------------
|
||||
|
||||
- When using **cherrysh**, input ``exit`` to exit adb mode
|
||||
- When using **msh**, you need to input ``adb_exit`` in **msh** to exit adb mode
|
||||
|
||||
.. figure:: img/cherryadb.png
|
||||
|
||||
.. figure:: img/rtt_adb_shell2.png
|
||||
10
docs/en/demo/usbd_audiov1.rst
Executable file
@@ -0,0 +1,10 @@
|
||||
AudioV1 Device
|
||||
=================
|
||||
|
||||
UAC1 demo refers to `demo/audio_v1_*.c` template.
|
||||
|
||||
When using UAC1.0, pay attention to the following points:
|
||||
|
||||
- When using Windows, when modifying any descriptor parameters, you must synchronously modify the string descriptor and uninstall the driver, otherwise Windows will consider the device unchanged and continue to use the old driver, causing device recognition failure. Linux is not subject to this restriction.
|
||||
- Download RemoveGhostDev64.exe from the QQ group files to automatically delete all USB registered driver information, eliminating the need for the first step
|
||||
- Prohibit adding print statements and time-consuming operations in interrupts, otherwise it will affect USB transmission according to interval
|
||||
10
docs/en/demo/usbd_audiov2.rst
Executable file
@@ -0,0 +1,10 @@
|
||||
AudioV2 Device
|
||||
=================
|
||||
|
||||
When using UAC2.0, please note the following points:
|
||||
|
||||
- On Windows, when modifying any parameter in the descriptor, the string descriptor must be modified synchronously and the driver must be uninstalled. Otherwise, Windows will think the device has not changed and continue to use the old driver, resulting in device recognition failure. Linux is not subject to this limitation.
|
||||
- You can download RemoveGhostDev64.exe from the QQ group files to automatically delete all USB registered driver information, eliminating the need for the first step
|
||||
- Windows 10 UAC2.0 functionality is incomplete, please use Windows 11 to test UAC2.0 functionality. Linux is not subject to this limitation
|
||||
- Windows has calculation errors in the sampling rate range setting for multi-channel (more than 2 channels). For example, if you set 8K~96K, the actual range is greater than or equal to 8K and less than 96K, not less than or equal to 96K. Linux is not subject to this limitation
|
||||
- Prohibit adding prints and time-consuming operations in interrupts, otherwise it will affect USB transmission according to interval
|
||||
104
docs/en/demo/usbd_cdc_acm.rst
Executable file
@@ -0,0 +1,104 @@
|
||||
CDC ACM Device
|
||||
=================
|
||||
|
||||
This demo mainly demonstrates CDC ACM functionality. Reference the `demo/cdc_acm_template.c` template. Includes transmission/reception testing, DTR control, ZLP testing, and performance testing.
|
||||
|
||||
- Allocate read/write buffers for data transmission/reception. Buffers need to be modified with nocache. Here we use 2048 bytes for both read and write for subsequent ZLP testing and performance testing.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_buffer[2048]; /* 2048 is only for test speed , please use CDC_MAX_MPS for common*/
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t write_buffer[2048];
|
||||
|
||||
|
||||
- In the protocol stack event callback, we need to start the first transmission after enumeration is complete and clear the related flags. This can be done in the reset event or in the configured event.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
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:
|
||||
ep_tx_busy_flag = false;
|
||||
/* setup first out ep read transfer */
|
||||
usbd_ep_start_read(busid, CDC_OUT_EP, read_buffer, 2048);
|
||||
break;
|
||||
case USBD_EVENT_SET_REMOTE_WAKEUP:
|
||||
break;
|
||||
case USBD_EVENT_CLR_REMOTE_WAKEUP:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- Continue to initiate reception in the reception complete interrupt; determine whether to send ZLP in the transmission complete interrupt.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_cdc_acm_bulk_out(uint8_t busid, 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(busid, CDC_OUT_EP, read_buffer, 2048);
|
||||
}
|
||||
|
||||
void usbd_cdc_acm_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
|
||||
{
|
||||
USB_LOG_RAW("actual in len:%d\r\n", nbytes);
|
||||
|
||||
if ((nbytes % usbd_get_ep_mps(busid, ep)) == 0 && nbytes) {
|
||||
/* send zlp */
|
||||
usbd_ep_start_write(busid, CDC_IN_EP, NULL, 0);
|
||||
} else {
|
||||
ep_tx_busy_flag = false;
|
||||
}
|
||||
}
|
||||
|
||||
- The following is for testing DTR functionality and controlling USB transmission. DTR and RTS are only used in conjunction with UART; for pure USB, they are not very useful - this is just for testing. DTR switch uses any serial port host computer and check DTR.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_cdc_acm_set_dtr(uint8_t busid, uint8_t intf, bool dtr)
|
||||
{
|
||||
if (dtr) {
|
||||
dtr_enable = 1;
|
||||
} else {
|
||||
dtr_enable = 0;
|
||||
}
|
||||
}
|
||||
|
||||
- Keep calling send in the main function
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void cdc_acm_data_send_with_dtr_test(uint8_t busid)
|
||||
{
|
||||
if (dtr_enable) {
|
||||
ep_tx_busy_flag = true;
|
||||
usbd_ep_start_write(busid, CDC_IN_EP, write_buffer, 2048);
|
||||
while (ep_tx_busy_flag) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- Note that we set the length to 2048 for testing ZLP functionality. In actual use, the receive length should use CDC_MAX_MPS. See :ref:`usb_ext` for specific reasons.
|
||||
- For performance testing, use tools/test_srcipts/test_cdc_speed.py and remove the print statements in `usbd_cdc_acm_bulk_out` and `usbd_cdc_acm_bulk_in` before testing, otherwise it will affect the test results.
|
||||
|
||||
|
||||
In addition, for CDC ACM with OS, we usually use asynchronous read and store data in a ringbuffer, and use synchronous write with semaphore.
|
||||
4
docs/en/demo/usbd_ecm.rst
Executable file
@@ -0,0 +1,4 @@
|
||||
CDC ECM Device
|
||||
=================
|
||||
|
||||
ECM demo refers to the `demo/cdc_ecm*.c` template. By default it interfaces with lwip protocol stack, and the upper layer can use lwip api.
|
||||
4
docs/en/demo/usbd_hid.rst
Executable file
@@ -0,0 +1,4 @@
|
||||
HID Device
|
||||
=================
|
||||
|
||||
HID functionality is relatively simple, so no detailed explanation is needed. Note that when using the HID custom example, it needs to be used with `tools/test_srcipts/test_hid_inout.py` (with report ID functionality).
|
||||
39
docs/en/demo/usbd_msc.rst
Executable file
@@ -0,0 +1,39 @@
|
||||
MSC Device
|
||||
=================
|
||||
|
||||
This section mainly demonstrates USB mass storage device functionality. By default, RAM is used as storage medium to simulate a USB drive.
|
||||
|
||||
- Implement read/write and capacity acquisition interfaces for the USB drive. Note that the capacity block_num is virtual - there aren't actually that many blocks. Read/write data exceeding BLOCK_COUNT will be discarded.
|
||||
|
||||
block_size is generally 512/2048/4096.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_msc_get_cap(uint8_t busid, uint8_t lun, uint32_t *block_num, uint32_t *block_size)
|
||||
{
|
||||
*block_num = 1000; //Pretend having so many buffer,not has actually.
|
||||
*block_size = BLOCK_SIZE;
|
||||
}
|
||||
int usbd_msc_sector_read(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length)
|
||||
{
|
||||
if (sector < BLOCK_COUNT)
|
||||
memcpy(buffer, mass_block[sector].BlockSpace, length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_msc_sector_write(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length)
|
||||
{
|
||||
if (sector < BLOCK_COUNT)
|
||||
memcpy(mass_block[sector].BlockSpace, buffer, length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
- By default, the above APIs execute in interrupt context. If you need to execute in non-interrupt context, you can choose the following:
|
||||
|
||||
1. In bare metal, enable `CONFIG_USBDEV_MSC_POLLING` and call `usbd_msc_polling` in while1, then read/write functions execute in while1.
|
||||
|
||||
2. In OS, enable `CONFIG_USBDEV_MSC_THREAD`, then read/write functions execute in thread.
|
||||
|
||||
- Modifying `CONFIG_USBDEV_MSC_BUFSIZE` will affect U disk read/write speed. It must be an integer multiple of block_size, of course, it will also increase RAM usage.
|
||||
|
||||
- If RAM example works but doesn't work after changing medium to SD or FLASH, it must be a medium driver problem.
|
||||
6
docs/en/demo/usbd_mtp.rst
Executable file
@@ -0,0 +1,6 @@
|
||||
MTP Device
|
||||
=================
|
||||
|
||||
MTP demo references the `demo/mtp_template.c` template. Adapted for FatFS file system by default (`platform/fatfs/usbd_fatfs_mtp.c`).
|
||||
|
||||
.. note:: MTP is commercially charged and does not provide open source MTP driver code. Please contact official support to purchase authorization.
|
||||
4
docs/en/demo/usbd_rndis.rst
Executable file
@@ -0,0 +1,4 @@
|
||||
CDC RNDIS Device
|
||||
=================
|
||||
|
||||
RNDIS demo refers to `demo/cdc_rndis*.c` template. By default it interfaces with lwip protocol stack, the upper layer can use lwip api.
|
||||
44
docs/en/demo/usbd_vendor.rst
Executable file
@@ -0,0 +1,44 @@
|
||||
Writing Vendor Device Driver
|
||||
============================================
|
||||
|
||||
This section mainly introduces how to write a vendor device driver.
|
||||
|
||||
- First copy a class/template/usbd_xxx.c file
|
||||
- Implement the following three callback functions. Generally speaking, vendor drivers only need to implement vendor_handlerDevice 驱动编写
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
intf->class_interface_handler = xxx_class_interface_request_handler;
|
||||
intf->class_endpoint_handler = NULL;
|
||||
intf->vendor_handler = NULL;
|
||||
intf->notify_handler = xxx_notify_handler;
|
||||
|
||||
- Example as follows
|
||||
|
||||
case1 demonstrates processing of host IN data, copying data to *data and specifying the length of *len. The protocol stack will automatically send to the host without requiring users to manually call send API.
|
||||
|
||||
case2 demonstrates processing of host OUT data. When this function is executed, it means all data has been received and can directly read data from *data with length *len.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
static int xxx_vendor_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
|
||||
{
|
||||
USB_LOG_WRN("XXX Class request: "
|
||||
"bRequest 0x%02x\r\n",
|
||||
setup->bRequest);
|
||||
|
||||
switch (setup->bRequest) {
|
||||
case 1:
|
||||
memcpy(*data, xxx, sizeof(xxx));
|
||||
*len = sizeof(xxx);
|
||||
case 2:
|
||||
hexdump(*data, *len);
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled XXX Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
- Finally register the interface using the form usbd_add_interface(busid, usbd_xxx_init_intf(&intf))
|
||||
83
docs/en/demo/usbd_video.rst
Executable file
@@ -0,0 +1,83 @@
|
||||
USB Video Device
|
||||
=================
|
||||
|
||||
This section mainly demonstrates USB UVC functionality, supporting YUYV, MJPEG, H264 formats. For demonstration convenience, static images are used throughout.
|
||||
|
||||
The demo includes **video_static_yuyv_template**, **video_static_mjpeg_template**, **video_static_h264_template**, with only descriptors and image data being different.
|
||||
|
||||
- In high-speed mode, the default maximum is 1024 bytes, but if the chip supports additional transactions, it can be configured up to 2048 bytes or 3072 bytes, which can improve transmission efficiency.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
#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
|
||||
|
||||
- Usually only need to modify WIDTH and HEIGHT
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
#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)
|
||||
|
||||
- USB endpoint configuration, default interval is 1, which is 1ms in full-speed mode and 125us in high-speed mode. Synchronization type uses asynchronous mode.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
/* 1.2.2.2 Standard VideoStream Isochronous Video Data Endpoint Descriptor */
|
||||
USB_ENDPOINT_DESCRIPTOR_INIT(VIDEO_IN_EP, 0x05, VIDEO_PACKET_SIZE, 0x01),
|
||||
|
||||
|
||||
- Use `usbd_video_stream_start_write` to transfer data. The final **do_copy** option indicates whether to copy data to packet_buffer.
|
||||
If copy is not selected, header information will be directly filled in the original image data and sent directly, achieving zero copy functionality.
|
||||
|
||||
- Because static data is provided and cannot be modified, a new frame_buffer needs to be allocated for image transmission. In actual camera integration scenarios, dynamic data is used and the camera's data buffer can be used directly.
|
||||
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_video_iso_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
|
||||
{
|
||||
if (usbd_video_stream_split_transfer(busid, ep)) {
|
||||
/* one frame has done */
|
||||
iso_tx_busy = false;
|
||||
}
|
||||
}
|
||||
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t packet_buffer[MAX_PAYLOAD_SIZE];
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t frame_buffer[32 * 1024];
|
||||
|
||||
void video_test(uint8_t busid)
|
||||
{
|
||||
memset(packet_buffer, 0, sizeof(packet_buffer));
|
||||
|
||||
while (1) {
|
||||
if (tx_flag) {
|
||||
iso_tx_busy = true;
|
||||
memcpy(frame_buffer, cherryusb_mjpeg, sizeof(cherryusb_mjpeg)); // cherryusb_mjpeg is a static MJPEG frame buffer, so we need copy it to frame_buffer
|
||||
usbd_video_stream_start_write(busid, VIDEO_IN_EP, packet_buffer, (uint8_t *)frame_buffer, sizeof(cherryusb_mjpeg), false);
|
||||
while (iso_tx_busy) {
|
||||
if (tx_flag == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
21
docs/en/demo/usbd_webusb.rst
Executable file
@@ -0,0 +1,21 @@
|
||||
WebUSB Device
|
||||
=================
|
||||
|
||||
This demo mainly demonstrates webusb functionality. Webusb is mainly used to pop up web pages and access USB devices. The example uses webusb_hid_template.c.
|
||||
|
||||
- When registering descriptors, just register BOS, MSOSV2, WEBUSB descriptors.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
usbd_bos_desc_register(busid, &bos_desc);
|
||||
usbd_msosv2_desc_register(busid, &msosv2_desc);
|
||||
usbd_webusb_desc_register(busid, &webusb_url_desc);
|
||||
|
||||
- Add an interface descriptor for webusb
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
USB_INTERFACE_DESCRIPTOR_INIT(USBD_WEBUSB_INTF_NUM, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00)
|
||||
|
||||
- The rest use hid descriptors, no further elaboration
|
||||
- After enumeration is completed, webpage information will pop up in the lower right corner of the computer, click to open the webpage
|
||||
55
docs/en/demo/usbd_winusb.rst
Executable file
@@ -0,0 +1,55 @@
|
||||
WinUSB Device
|
||||
=================
|
||||
|
||||
This section mainly introduces the winusb driver. Winusb is a general driver provided by Windows to allow users to access USB custom class devices in a user-friendly manner. It is essentially CDC ACM, but without baud rate setting commands.
|
||||
WINUSB versions are divided into V1/V2 versions according to USB versions. V2 version requires BOS descriptor, while V1 version does not. **V2 version requires setting USB2.1 version number in device descriptor**.
|
||||
|
||||
.. note:: Changing any winusb descriptor configuration may result in successful enumeration but inability to recognize the device. You need to delete all registry entries under Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\usbflags, then unplug and replug the device to take effect.
|
||||
|
||||
- V1 version descriptor registration
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
const struct usb_descriptor winusbv1_descriptor = {
|
||||
.device_descriptor_callback = device_descriptor_callback,
|
||||
.config_descriptor_callback = config_descriptor_callback,
|
||||
.device_quality_descriptor_callback = device_quality_descriptor_callback,
|
||||
.string_descriptor_callback = string_descriptor_callback,
|
||||
.msosv1_descriptor = &msosv1_desc
|
||||
};
|
||||
|
||||
OR
|
||||
|
||||
usbd_msosv1_desc_register(busid, &msosv1_desc);
|
||||
|
||||
- V2 version descriptor registration
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
const struct usb_descriptor winusbv2_descriptor = {
|
||||
.device_descriptor_callback = device_descriptor_callback,
|
||||
.config_descriptor_callback = config_descriptor_callback,
|
||||
.device_quality_descriptor_callback = device_quality_descriptor_callback,
|
||||
.string_descriptor_callback = string_descriptor_callback,
|
||||
.msosv2_descriptor = &msosv2_desc,
|
||||
.bos_descriptor = &bos_desc,
|
||||
};
|
||||
|
||||
OR
|
||||
|
||||
usbd_bos_desc_register(busid, &bos_desc);
|
||||
usbd_msosv2_desc_register(busid, &msosv2_desc);
|
||||
|
||||
|
||||
- Interface descriptor registration
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
/* Interface 0 */
|
||||
USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x02),
|
||||
/* Endpoint OUT 2 */
|
||||
USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP, USB_ENDPOINT_TYPE_BULK, WINUSB_EP_MPS, 0x00),
|
||||
/* Endpoint IN 1 */
|
||||
USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP, USB_ENDPOINT_TYPE_BULK, WINUSB_EP_MPS, 0x00),
|
||||
|
||||
- Read and write operations are the same as CDC ACM, no further elaboration
|
||||
4
docs/en/demo/usbh_audio.rst
Executable file
@@ -0,0 +1,4 @@
|
||||
Audio Host
|
||||
=================
|
||||
|
||||
.. note:: Host UAC is commercially charged. Please contact the official for purchase authorization.
|
||||
2
docs/en/demo/usbh_bluetooth.rst
Executable file
@@ -0,0 +1,2 @@
|
||||
BTBLE Host
|
||||
=================
|
||||
55
docs/en/demo/usbh_hid.rst
Executable file
@@ -0,0 +1,55 @@
|
||||
HID Host
|
||||
=================
|
||||
|
||||
This section mainly introduces the use of Host HID class.
|
||||
|
||||
- Create a one-time thread in HID enumeration completion callback
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
|
||||
void usbh_hid_run(struct usbh_hid *hid_class)
|
||||
{
|
||||
usb_osal_thread_create("usbh_hid", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_hid_thread, hid_class);
|
||||
}
|
||||
|
||||
void usbh_hid_stop(struct usbh_hid *hid_class)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
- Here we use the asynchronous operation of usbh_submit_urb, process data in interrupt and continue to receive next data.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
static void usbh_hid_thread(void *argument)
|
||||
{
|
||||
int ret;
|
||||
struct usbh_hid *hid_class = (struct usbh_hid *)argument;
|
||||
;
|
||||
|
||||
/* test with only one buffer, if you have more hid class, modify by yourself */
|
||||
|
||||
/* Suggest you to use timer for int transfer and use ep interval */
|
||||
usbh_int_urb_fill(&hid_class->intin_urb, hid_class->hport, hid_class->intin, hid_buffer, hid_class->intin->wMaxPacketSize, 0, usbh_hid_callback, hid_class);
|
||||
ret = usbh_submit_urb(&hid_class->intin_urb);
|
||||
if (ret < 0) {
|
||||
goto delete;
|
||||
}
|
||||
// clang-format off
|
||||
delete:
|
||||
usb_osal_thread_delete(NULL);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
- Of course, you can also not use asynchronous operations, but use synchronous operations with timeout.
|
||||
- HID uses interrupt transfer, so normally we need to set a timer based on **bInterval** to trigger interrupt transfer at regular intervals. This is not used in the demo. If you have precise time requirements, you can choose to use a timer to trigger asynchronous sending.
|
||||
- Taking hub communication as an example, a one-time timer is used, but a periodic timer can also be used.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
hub->int_timer = usb_osal_timer_create("hubint_tim", USBH_GET_URB_INTERVAL(hub->intin->bInterval, hport->speed) / 1000, hub_int_timeout, hub, 0);
|
||||
|
||||
.. note::
|
||||
|
||||
Here `USBH_GET_URB_INTERVAL` is a macro definition used to calculate the URB transfer interval time based on binterval. The unit is us, while the timer minimum is ms, so it needs to be divided by 1000. For intervals less than or equal to 1ms, no timer is needed.
|
||||
56
docs/en/demo/usbh_msc.rst
Executable file
@@ -0,0 +1,56 @@
|
||||
MSC Host
|
||||
=================
|
||||
|
||||
This section mainly introduces the use of Host MSC. Read and write functions are implemented with the help of FATFS.
|
||||
|
||||
- Register a thread in the callback after MSC enumeration is completed, used for read and write operations.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbh_msc_run(struct usbh_msc *msc_class)
|
||||
{
|
||||
usb_osal_thread_create("usbh_msc", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_msc_thread, msc_class);
|
||||
}
|
||||
|
||||
void usbh_msc_stop(struct usbh_msc *msc_class)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
- Without using fatfs, directly use usbh_msc_scsi_read10 or usbh_msc_scsi_write10 functions for read and write operations.
|
||||
- If using fatfs, you need to call fatfs interfaces in usbh_msc_thread for read and write operations. For MSC read/write adaptation to fatfs, refer to `platform/fatfs/usbh_fatfs.c`
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
static void usbh_msc_thread(void *argument)
|
||||
{
|
||||
int ret;
|
||||
struct usbh_msc *msc_class = (struct usbh_msc *)argument;
|
||||
|
||||
/* test with only one buffer, if you have more msc class, modify by yourself */
|
||||
#if 1
|
||||
/* get the partition table */
|
||||
ret = usbh_msc_scsi_read10(msc_class, 0, partition_table, 1);
|
||||
if (ret < 0) {
|
||||
USB_LOG_RAW("scsi_read10 error,ret:%d\r\n", ret);
|
||||
goto delete;
|
||||
}
|
||||
for (uint32_t i = 0; i < 512; i++) {
|
||||
if (i % 16 == 0) {
|
||||
USB_LOG_RAW("\r\n");
|
||||
}
|
||||
USB_LOG_RAW("%02x ", partition_table[i]);
|
||||
}
|
||||
USB_LOG_RAW("\r\n");
|
||||
#endif
|
||||
|
||||
#if TEST_USBH_MSC_FATFS
|
||||
usb_msc_fatfs_test();
|
||||
#endif
|
||||
// clang-format off
|
||||
delete:
|
||||
usb_osal_thread_delete(NULL);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
- Finally, after processing is completed or failed, delete the thread.
|
||||
167
docs/en/demo/usbh_net.rst
Executable file
@@ -0,0 +1,167 @@
|
||||
Network Host
|
||||
=================
|
||||
|
||||
This section mainly introduces the use of Host USB network cards. The following USB ne- Because the USB network card has been internally connected to LWIP, users can directly use LWIP APIs without worrying about USB implementation.
|
||||
|
||||
USB Network Card LWIP Configuration Macro Related Notes
|
||||
-----------------------------------------------------------
|
||||
|
||||
**LWIP_TCPIP_CORE_LOCKING_INPUT** is used to not use lwip built-in tcpip thread, but use USB's own receive processing thread.
|
||||
|
||||
**LWIP_TCPIP_CORE_LOCKING** is enabled by default in current lwip versions, and it is also recommended to be mandatory.
|
||||
|
||||
**PBUF_POOL_BUFSIZE** is recommended to be greater than 1600, used with LWIP_TCPIP_CORE_LOCKING_INPUT, because we provide zero copy method using static pbuf instead of copying data into pbuf.
|
||||
|
||||
**TCPIP_THREAD_STACKSIZE** is recommended to be greater than 1K to prevent stack overflow.are currently supported and tested:
|
||||
|
||||
- 4G network cards: EC20(ECM/RNDIS), mobile phones (RNDIS), SIMCOM7600(RNDIS), ML307R(RNDIS), AIR780(RNDIS)
|
||||
|
||||
.. caution:: Please note that some 4G network cards do not have auto-dial functionality by default. Please replace the firmware or use AT commands to configure auto-dial, otherwise you cannot get an IP.
|
||||
|
||||
- USB Ethernet cards: ASIX AX88772, REALTEK RTL8152
|
||||
- USB WIFI cards: Bouffalo Lab BL616 (RNDIS/ECM)
|
||||
|
||||
USB Network Card Related Macros and Files
|
||||
--------------------------------------------------
|
||||
|
||||
The network card related macros are as follows, mainly used to register network card drivers according to different network components:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
// #define CONFIG_USBHOST_PLATFORM_CDC_ECM
|
||||
// #define CONFIG_USBHOST_PLATFORM_CDC_RNDIS
|
||||
// #define CONFIG_USBHOST_PLATFORM_CDC_NCM
|
||||
// #define CONFIG_USBHOST_PLATFORM_ASIX
|
||||
// #define CONFIG_USBHOST_PLATFORM_RTL8152
|
||||
|
||||
.. note:: If Kconfig system is used, the above macros are automatically generated. For other platforms, please define manually.
|
||||
|
||||
USB network card transmission layer has been connected to relevant network components, listed as follows:
|
||||
|
||||
- Custom OS + LWIP please use **platform/lwip/usbh_lwip.c**, need to include this file yourself and enable the above relevant macros. Call `tcpip_init(NULL, NULL)` before initializing USB
|
||||
- RT-THREAD + LWIP please use **platform/rtthread/usbh_lwip.c**, automatically select this file after enabling corresponding network card driver in Kconfig, automatically call `tcpip_init(NULL, NULL)` after selecting rt-thread lwip
|
||||
- ESP-IDF + LWIP please use **platform/freertos/usbh_net.c**, automatically select this file after enabling corresponding network card driver in Kconfig, and call `esp_netif_init()` + `esp_event_loop_create_default()` before initializing USB
|
||||
- NUTTX + NUTTX network component please use **platform/nuttx/usbh_net.c**, automatically select this file after enabling corresponding network card driver in Kconfig, automatically call after selecting network component
|
||||
|
||||
.. note:: If adding code yourself, don't forget to add USB network card driver related source files, such as **class/usbh_cdc_ecm.c**. So we recommend using with corresponding platforms to save the trouble of adding files yourself
|
||||
|
||||
USB Network Card Connection Process
|
||||
---------------------------------------------
|
||||
|
||||
The following example shows the LWIP connection process.
|
||||
|
||||
- After USB network card enumeration is completed, the `usbh_xxx_run` function will be **automatically** called, at which time netif driver is registered, and DHCP client and IP acquisition timer are started.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbh_cdc_ecm_run(struct usbh_cdc_ecm *cdc_ecm_class)
|
||||
{
|
||||
struct netif *netif = &g_cdc_ecm_netif;
|
||||
|
||||
netif->hwaddr_len = 6;
|
||||
memcpy(netif->hwaddr, cdc_ecm_class->mac, 6);
|
||||
|
||||
IP4_ADDR(&g_ipaddr, 0, 0, 0, 0);
|
||||
IP4_ADDR(&g_netmask, 0, 0, 0, 0);
|
||||
IP4_ADDR(&g_gateway, 0, 0, 0, 0);
|
||||
|
||||
netif = netif_add(netif, &g_ipaddr, &g_netmask, &g_gateway, NULL, usbh_cdc_ecm_if_init, tcpip_input);
|
||||
netif_set_default(netif);
|
||||
while (!netif_is_up(netif)) {
|
||||
}
|
||||
|
||||
dhcp_handle = usb_osal_timer_create("dhcp", 200, dhcp_timeout, netif, true);
|
||||
if (dhcp_handle == NULL) {
|
||||
USB_LOG_ERR("timer creation failed! \r\n");
|
||||
while (1) {
|
||||
}
|
||||
}
|
||||
|
||||
usb_osal_thread_create("usbh_cdc_ecm_rx", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_cdc_ecm_rx_thread, NULL);
|
||||
#if LWIP_DHCP
|
||||
dhcp_start(netif);
|
||||
usb_osal_timer_start(dhcp_handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
- `usbh_lwip_eth_output_common` is used to assemble transmitted pbuf into USB network card data packets
|
||||
- `usbh_lwip_eth_input_common` is used to assemble USB network card data into pbuf
|
||||
- Actual network card transmission and reception processing
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
static err_t usbh_cdc_ecm_linkoutput(struct netif *netif, struct pbuf *p)
|
||||
{
|
||||
int ret;
|
||||
(void)netif;
|
||||
|
||||
usbh_lwip_eth_output_common(p, usbh_cdc_ecm_get_eth_txbuf());
|
||||
ret = usbh_cdc_ecm_eth_output(p->tot_len);
|
||||
if (ret < 0) {
|
||||
return ERR_BUF;
|
||||
} else {
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
void usbh_cdc_ecm_eth_input(uint8_t *buf, uint32_t buflen)
|
||||
{
|
||||
usbh_lwip_eth_input_common(&g_cdc_ecm_netif, buf, buflen);
|
||||
}
|
||||
|
||||
- After the USB network card is unplugged, the `usbh_xxx_stop` function will be **automatically** called, at which time you need to stop the DHCP client, delete the timer, and remove the netif.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbh_cdc_ecm_stop(struct usbh_cdc_ecm *cdc_ecm_class)
|
||||
{
|
||||
struct netif *netif = &g_cdc_ecm_netif;
|
||||
(void)cdc_ecm_class;
|
||||
|
||||
#if LWIP_DHCP
|
||||
dhcp_stop(netif);
|
||||
dhcp_cleanup(netif);
|
||||
usb_osal_timer_delete(dhcp_handle);
|
||||
#endif
|
||||
netif_set_down(netif);
|
||||
netif_remove(netif);
|
||||
}
|
||||
|
||||
- Because the USB network card has been internally connected to LWIP, users can directly use LWIP APIs without worrying about USB implementation.
|
||||
|
||||
USB Network Card LWIP Configuration Macro Related Notes
|
||||
--------------------------------------------------------------
|
||||
|
||||
**LWIP_TCPIP_CORE_LOCKING_INPUT** is used to not use lwip built-in tcpip thread, but use USB's own receive processing thread.
|
||||
|
||||
**LWIP_TCPIP_CORE_LOCKING** is enabled by default in current lwip versions, and it is also recommended to be mandatory.
|
||||
|
||||
**PBUF_POOL_BUFSIZE** is recommended to be greater than 1600, used with LWIP_TCPIP_CORE_LOCKING_INPUT, because we provide zero copy method using static pbuf instead of copying data into pbuf.
|
||||
|
||||
**TCPIP_THREAD_STACKSIZE** is recommended to be greater than 1K to prevent stack overflow.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
#if LWIP_TCPIP_CORE_LOCKING_INPUT != 1
|
||||
#warning suggest you to set LWIP_TCPIP_CORE_LOCKING_INPUT to 1, usb handles eth input with own thread
|
||||
#endif
|
||||
|
||||
#if LWIP_TCPIP_CORE_LOCKING != 1
|
||||
#error must set LWIP_TCPIP_CORE_LOCKING to 1
|
||||
#endif
|
||||
|
||||
#if PBUF_POOL_BUFSIZE < 1600
|
||||
#error PBUF_POOL_BUFSIZE must be larger than 1600
|
||||
#endif
|
||||
|
||||
#if TCPIP_THREAD_STACKSIZE < 1024
|
||||
#error TCPIP_THREAD_STACKSIZE must be >= 1024
|
||||
#endif
|
||||
|
||||
|
||||
Summary
|
||||
--------------
|
||||
|
||||
.. note:: Through the above content, we can see that CherryUSB's support for USB network cards is very comprehensive. Users only need to enable corresponding macros or check options to achieve automatic recognition and driver registration of USB network cards, without manually initializing network card related configurations. Users only need to focus on the application layer, which greatly facilitates user usage.
|
||||
|
||||
For specific porting articles, please refer to developers' notes https://club.rt-thread.org/ask/article/5cf3e9e0b2d95800.html
|
||||
196
docs/en/demo/usbh_serial.rst
Executable file
@@ -0,0 +1,196 @@
|
||||
Serial Host
|
||||
=================
|
||||
|
||||
This section mainly introduces the usage of the Host serial framework. The Serial framework currently supports CDC ACM, FTDI, CP210x, CH34x, PL2303, and GSM drivers.
|
||||
|
||||
.. figure:: img/usbh_serial.png
|
||||
|
||||
Currently supports two usage methods: one is using native CherryUSB usbhost serial API for operations, and the other is based on platform-wrapped APIs such as RT-Thread device API and NuttX POSIX API.
|
||||
|
||||
The following demonstrates using CherryUSB usbhost serial API for serial loopback testing with blocking transmission and asynchronous reception:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
struct usbh_serial *serial;
|
||||
|
||||
serial = usbh_serial_open("/dev/ttyACM0", USBH_SERIAL_O_RDWR | USBH_SERIAL_O_NONBLOCK);
|
||||
if (serial == NULL) {
|
||||
serial = usbh_serial_open("/dev/ttyUSB0", USBH_SERIAL_O_RDWR | USBH_SERIAL_O_NONBLOCK);
|
||||
if (serial == NULL) {
|
||||
USB_LOG_RAW("no serial device found\r\n");
|
||||
goto delete;
|
||||
}
|
||||
}
|
||||
|
||||
struct usbh_serial_termios termios;
|
||||
|
||||
memset(&termios, 0, sizeof(termios));
|
||||
termios.baudrate = 115200;
|
||||
termios.stopbits = 0;
|
||||
termios.parity = 0;
|
||||
termios.databits = 8;
|
||||
termios.rtscts = false;
|
||||
termios.rx_timeout = 0;
|
||||
ret = usbh_serial_control(serial, USBH_SERIAL_CMD_SET_ATTR, &termios);
|
||||
if (ret < 0) {
|
||||
USB_LOG_RAW("set serial attr error, ret:%d\r\n", ret);
|
||||
goto delete_with_close;
|
||||
}
|
||||
|
||||
serial_tx_bytes = 0;
|
||||
while (1) {
|
||||
ret = usbh_serial_write(serial, serial_tx_buffer, sizeof(serial_tx_buffer));
|
||||
if (ret < 0) {
|
||||
USB_LOG_RAW("serial write error, ret:%d\r\n", ret);
|
||||
goto delete_with_close;
|
||||
} else {
|
||||
serial_tx_bytes += ret;
|
||||
|
||||
if (serial_tx_bytes == SERIAL_TEST_LEN) {
|
||||
USB_LOG_RAW("send over\r\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
volatile uint32_t wait_timeout = 0;
|
||||
serial_rx_bytes = 0;
|
||||
while (1) {
|
||||
ret = usbh_serial_read(serial, &serial_rx_data[serial_rx_bytes], SERIAL_TEST_LEN - serial_rx_bytes);
|
||||
if (ret < 0) {
|
||||
USB_LOG_RAW("serial read error, ret:%d\r\n", ret);
|
||||
goto delete_with_close;
|
||||
} else {
|
||||
serial_rx_bytes += ret;
|
||||
|
||||
if (serial_rx_bytes == SERIAL_TEST_LEN) {
|
||||
USB_LOG_RAW("receive over\r\n");
|
||||
for (uint32_t i = 0; i < SERIAL_TEST_LEN; i++) {
|
||||
if (serial_rx_data[i] != 0xa5) {
|
||||
USB_LOG_RAW("serial loopback data error at index %d, data: 0x%02x\r\n", (unsigned int)i, serial_rx_data[i]);
|
||||
goto delete_with_close;
|
||||
}
|
||||
}
|
||||
serial_test_success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
wait_timeout++;
|
||||
|
||||
if (wait_timeout > 500) { // 5s
|
||||
USB_LOG_RAW("serial read timeout\r\n");
|
||||
goto delete_with_close;
|
||||
}
|
||||
|
||||
usb_osal_msleep(10);
|
||||
}
|
||||
|
||||
usbh_serial_close(serial);
|
||||
|
||||
.. caution:: Note that the example uses a simple send-then-read approach, so the total length sent cannot exceed CONFIG_USBHOST_SERIAL_RX_SIZE. For normal TX/RX usage, please perform them separately.
|
||||
|
||||
Users need to consider the following three scenarios:
|
||||
|
||||
- USB2TTL device + baud rate enabled (USB2TTL devices must enable baud rate), in this case you need to use `usbh_serial_write` and `usbh_serial_read` to send and receive data, **and read operations need to be timely to prevent ringbuf data overflow and packet loss**. Cannot use `usbh_serial_cdc_write_async` and `usbh_serial_cdc_read_async`
|
||||
|
||||
- Pure USB device + baud rate not started, in this case you can use `usbh_serial_cdc_write_async` and `usbh_serial_cdc_read_async` for asynchronous send/receive data. For blocking, you can use `usbh_serial_write`, but cannot use `usbh_serial_read`.
|
||||
|
||||
- Pure USB device + baud rate started, same as 1, but the reception rate will be discounted (because of an extra layer of ringbuf). In this case, `usbh_serial_cdc_write_async` and `usbh_serial_cdc_read_async` cannot be used either. **If it is a GSM device, please use the first scenario**.
|
||||
|
||||
.. note:: Simply put, if receiving data requires going through a ringbuf layer, please use the first scenario.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
[I/usbh_hub] New full-speed device on Bus 0, Hub 1, Port 1 connected
|
||||
[I/usbh_core] New device found,idVendor:10c4,idProduct:ea60,bcdDevice:0100
|
||||
[I/usbh_core] The device has 1 bNumConfigurations
|
||||
[I/usbh_core] The device has 1 interfaces
|
||||
[I/usbh_core] Enumeration success, start loading class driver
|
||||
[I/usbh_core] Loading cp210x class driver on interface 0
|
||||
[I/usbh_cp210x] chip partnum: 0x02
|
||||
[I/usbh_cp210x] ulAmountInInQueue: 0, ulAmountInOutQueue: 0
|
||||
[I/usbh_serial] Ep=81 Attr=02 Mps=64 Interval=00 Mult=00
|
||||
[I/usbh_serial] Ep=01 Attr=02 Mps=64 Interval=00 Mult=00
|
||||
[I/usbh_serial] Register Serial Class: /dev/ttyUSB0 (cp210x)
|
||||
start serial loopback test, len: 1024
|
||||
send over
|
||||
receive over
|
||||
serial loopback test success
|
||||
[I/usbh_serial] Unregister Serial Class: /dev/ttyUSB0 (cp210x)
|
||||
[I/usbh_core] Device on Bus 0, Hub 1, Port 1 disconnected
|
||||
[I/usbh_hub] New high-speed device on Bus 0, Hub 1, Port 1 connected
|
||||
[I/usbh_core] New device found,idVendor:0403,idProduct:6010,bcdDevice:0700
|
||||
[I/usbh_core] The device has 1 bNumConfigurations
|
||||
[I/usbh_core] The device has 2 interfaces
|
||||
[I/usbh_core] Enumeration success, start loading class driver
|
||||
[I/usbh_core] Loading ftdi class driver on interface 0
|
||||
[I/usbh_ftdi] chip name: FT2232H
|
||||
[I/usbh_serial] Ep=81 Attr=02 Mps=512 Interval=00 Mult=00
|
||||
[I/usbh_serial] Ep=02 Attr=02 Mps=512 Interval=00 Mult=00
|
||||
[I/usbh_serial] Register Serial Class: /dev/ttyUSB0 (ftdi)
|
||||
[I/usbh_core] Loading ftdi class driver on interface 1
|
||||
[I/usbh_ftdi] chip name: FT2232H
|
||||
[I/usbh_serial] Ep=83 Attr=02 Mps=512 Interval=00 Mult=00
|
||||
[I/usbh_serial] Ep=04 Attr=02 Mps=512 Interval=00 Mult=00
|
||||
[I/usbh_serial] Register Serial Class: /dev/ttyUSB1 (ftdi)
|
||||
start serial loopback test, len: 1024
|
||||
send over
|
||||
receive over
|
||||
serial loopback test success
|
||||
[I/usbh_serial] Unregister Serial Class: /dev/ttyUSB0 (ftdi)
|
||||
[I/usbh_serial] Unregister Serial Class: /dev/ttyUSB1 (ftdi)
|
||||
[I/usbh_core] Device on Bus 0, Hub 1, Port 1 disconnected
|
||||
[I/usbh_hub] New full-speed device on Bus 0, Hub 1, Port 1 connected
|
||||
[I/usbh_core] New device found,idVendor:067b,idProduct:2303,bcdDevice:0300
|
||||
[I/usbh_core] The device has 1 bNumConfigurations
|
||||
[I/usbh_core] The device has 1 interfaces
|
||||
[I/usbh_core] Enumeration success, start loading class driver
|
||||
[I/usbh_core] Loading pl2303 class driver on interface 0
|
||||
[I/usbh_pl2303] Ep=81 Attr=03 Mps=10 Interval=01 Mult=00
|
||||
[I/usbh_pl2303] chip type: PL2303HX
|
||||
[I/usbh_serial] Ep=02 Attr=02 Mps=64 Interval=00 Mult=00
|
||||
[I/usbh_serial] Ep=83 Attr=02 Mps=64 Interval=00 Mult=00
|
||||
[I/usbh_serial] Register Serial Class: /dev/ttyUSB0 (pl2303)
|
||||
start serial loopback test, len: 1024
|
||||
send over
|
||||
receive over
|
||||
serial loopback test success
|
||||
[I/usbh_serial] Unregister Serial Class: /dev/ttyUSB0 (pl2303)
|
||||
[I/usbh_core] Device on Bus 0, Hub 1, Port 1 disconnected
|
||||
[W/usbh_hub] Failed to enable port 1
|
||||
[I/usbh_hub] New full-speed device on Bus 0, Hub 1, Port 1 connected
|
||||
[I/usbh_core] New device found,idVendor:1a86,idProduct:7523,bcdDevice:0264
|
||||
[I/usbh_core] The device has 1 bNumConfigurations
|
||||
[I/usbh_core] The device has 1 interfaces
|
||||
[I/usbh_core] Enumeration success, start loading class driver
|
||||
[I/usbh_core] Loading ch34x class driver on interface 0
|
||||
[I/usbh_ch43x] Ep=81 Attr=03 Mps=8 Interval=01 Mult=00
|
||||
[I/usbh_ch43x] chip version: 0x31
|
||||
[I/usbh_serial] Ep=82 Attr=02 Mps=32 Interval=00 Mult=00
|
||||
[I/usbh_serial] Ep=02 Attr=02 Mps=32 Interval=00 Mult=00
|
||||
[I/usbh_serial] Register Serial Class: /dev/ttyUSB0 (ch34x)
|
||||
start serial loopback test, len: 1024
|
||||
send over
|
||||
receive over
|
||||
serial loopback test success
|
||||
[I/usbh_serial] Unregister Serial Class: /dev/ttyUSB0 (ch34x)
|
||||
[I/usbh_core] Device on Bus 0, Hub 1, Port 1 disconnected
|
||||
[I/usbh_hub] New full-speed device on Bus 0, Hub 1, Port 1 connected
|
||||
[I/usbh_core] New device found,idVendor:42bf,idProduct:b210,bcdDevice:0217
|
||||
[I/usbh_core] The device has 1 bNumConfigurations
|
||||
[I/usbh_core] The device has 3 interfaces
|
||||
[I/usbh_core] Enumeration success, start loading class driver
|
||||
[E/usbh_core] Do not support Class:0xff, Subclass:0x01, Protocl:0x00 on interface 0
|
||||
[I/usbh_core] Loading cdc_acm class driver on interface 1
|
||||
[I/usbh_cdc_acm] Ep=85 Attr=03 Mps=64 Interval=00 Mult=00
|
||||
[I/usbh_serial] Ep=04 Attr=02 Mps=64 Interval=00 Mult=00
|
||||
[I/usbh_serial] Ep=83 Attr=02 Mps=64 Interval=00 Mult=00
|
||||
[I/usbh_serial] Register Serial Class: /dev/ttyACM0 (cdc_acm)
|
||||
[I/usbh_core] Loading cdc_data class driver on interface 2
|
||||
start serial loopback test, len: 1024
|
||||
send over
|
||||
receive over
|
||||
serial loopback test success
|
||||
[I/usbh_serial] Unregister Serial Class: /dev/ttyACM0 (cdc_acm)
|
||||
[I/usbh_core] Device on Bus 0, Hub 1, Port 1 disconnected
|
||||
|
||||
127
docs/en/demo/usbh_vendor.rst
Executable file
@@ -0,0 +1,127 @@
|
||||
Writing Vendor Host Driver
|
||||
============================================
|
||||
|
||||
This section mainly introduces how to write a vendor host driver.
|
||||
|
||||
- First copy a class/template/usbh_xxx.c file
|
||||
|
||||
- Define class driver and use CLASS_INFO_DEFINE prefix, so that after enumeration is completed, the protocol stack automatically finds the corresponding driver through usbd_class_find_driver.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
static const struct usbh_class_driver xxx_class_driver = {
|
||||
.driver_name = "xxx",
|
||||
.connect = usbh_xxx_connect,
|
||||
.disconnect = usbh_xxx_disconnect
|
||||
};
|
||||
|
||||
CLASS_INFO_DEFINE const struct usbh_class_info xxx_class_info = {
|
||||
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
|
||||
.bInterfaceClass = 0,
|
||||
.bInterfaceSubClass = 0,
|
||||
.bInterfaceProtocol = 0,
|
||||
.id_table = NULL,
|
||||
.class_driver = &xxx_class_driver
|
||||
};
|
||||
|
||||
|
||||
- Implement connect and disconnect functions. In the connect function, you need to allocate an xxx_class structure. In the disconnect function, release the urb and xxx_class.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
struct usbh_xxx {
|
||||
struct usbh_hubport *hport;
|
||||
struct usb_endpoint_descriptor *xxxin;
|
||||
struct usb_endpoint_descriptor *xxxout;
|
||||
struct usbh_urb xxxin_urb;
|
||||
struct usbh_urb xxxout_urb;
|
||||
|
||||
uint8_t intf; /* interface number */
|
||||
uint8_t minor;
|
||||
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
static int usbh_xxx_connect(struct usbh_hubport *hport, uint8_t intf)
|
||||
{
|
||||
struct usb_endpoint_descriptor *ep_desc;
|
||||
int ret;
|
||||
|
||||
struct usbh_xxx *xxx_class = usbh_xxx_class_alloc();
|
||||
if (xxx_class == NULL) {
|
||||
USB_LOG_ERR("Fail to alloc xxx_class\r\n");
|
||||
return -USB_ERR_NOMEM;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int usbh_xxx_disconnect(struct usbh_hubport *hport, uint8_t intf)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
struct usbh_xxx *xxx_class = (struct usbh_xxx *)hport->config.intf[intf].priv;
|
||||
|
||||
if (xxx_class) {
|
||||
if (xxx_class->xxxin) {
|
||||
usbh_kill_urb(&xxx_class->xxxin_urb);
|
||||
}
|
||||
|
||||
if (xxx_class->xxxout) {
|
||||
usbh_kill_urb(&xxx_class->xxxout_urb);
|
||||
}
|
||||
|
||||
if (hport->config.intf[intf].devname[0] != '\0') {
|
||||
USB_LOG_INFO("Unregister xxx Class:%s\r\n", hport->config.intf[intf].devname);
|
||||
usbh_xxx_stop(xxx_class);
|
||||
}
|
||||
|
||||
usbh_xxx_class_free(xxx_class);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
- Initialize endpoints
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
|
||||
ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
|
||||
if (ep_desc->bEndpointAddress & 0x80) {
|
||||
USBH_EP_INIT(xxx_class->intin, ep_desc);
|
||||
} else {
|
||||
USBH_EP_INIT(xxx_class->intout, ep_desc);
|
||||
}
|
||||
}
|
||||
|
||||
- Finally design send/receive APIs, design them as synchronous or asynchronous according to actual conditions.
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbh_xxx_in_transfer(struct usbh_xxx *xxx_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
|
||||
{
|
||||
int ret;
|
||||
struct usbh_urb *urb = &xxx_class->xxxin_urb;
|
||||
|
||||
usbh_xxx_urb_fill(urb, xxx_class->hport, xxx_class->xxxin, buffer, buflen, timeout, NULL, NULL);
|
||||
ret = usbh_submit_urb(urb);
|
||||
if (ret == 0) {
|
||||
ret = urb->actual_length;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int usbh_xxx_out_transfer(struct usbh_xxx *xxx_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
|
||||
{
|
||||
int ret;
|
||||
struct usbh_urb *urb = &xxx_class->xxxout_urb;
|
||||
|
||||
usbh_xxx_urb_fill(urb, xxx_class->hport, xxx_class->xxxout, buffer, buflen, timeout, NULL, NULL);
|
||||
ret = usbh_submit_urb(urb);
|
||||
if (ret == 0) {
|
||||
ret = urb->actual_length;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
4
docs/en/demo/usbh_video.rst
Executable file
@@ -0,0 +1,4 @@
|
||||
Video Host
|
||||
=================
|
||||
|
||||
.. note:: Host UVC is commercially charged. Please contact official support to purchase authorization.
|
||||
2
docs/en/demo/usbh_wifi.rst
Executable file
@@ -0,0 +1,2 @@
|
||||
WIFI Host
|
||||
=================
|
||||
160
docs/en/index.rst
Executable file
@@ -0,0 +1,160 @@
|
||||
.. CherryUSB User Guide documentation master file, created by
|
||||
sphinx-quickstart on Thu Nov 21 10:50:33 2019.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
CherryUSB User Guide
|
||||
====================================================================
|
||||
|
||||
CherryUSB is a small, lightweight, portable USB host and device protocol stack for embedded systems. CherryUSB offers the following advantages:
|
||||
|
||||
**Easy to Learn USB**
|
||||
|
||||
To facilitate user learning of USB fundamentals, enumeration, driver loading, and IP drivers, the written code has the following advantages:
|
||||
|
||||
- Streamlined code with simple logic and no complex C language syntax
|
||||
- Tree-structured programming with progressive code layers
|
||||
- Templated and simplified Class drivers and porting drivers
|
||||
- Clear API categorization (Device: initialization, class registration, command callbacks, data transmission; Host: initialization, class discovery, data transmission)
|
||||
|
||||
**Easy to Use USB**
|
||||
|
||||
To facilitate user interaction with USB interfaces, considering users' familiarity with UART and DMA, the designed data transmission interface has the following advantages:
|
||||
|
||||
- Equivalent to using UART TX DMA/UART RX DMA
|
||||
- No length restrictions on transmission/reception; users don't need to worry about USB packetization (porting drivers handle packetization)
|
||||
|
||||
**Easy to Achieve USB Performance**
|
||||
|
||||
Considering USB performance requirements to reach theoretical USB hardware bandwidth, the designed data transmission interface has the following advantages:
|
||||
|
||||
- Porting drivers directly interface with registers without abstraction layer encapsulation
|
||||
- Memory zero copy
|
||||
- DMA mode used when IP supports DMA (DMA provides hardware packetization functionality)
|
||||
- No length restrictions, facilitating hardware DMA interfacing and maximizing DMA advantages
|
||||
- Packetization handled in interrupt context
|
||||
|
||||
**Device Protocol Stack Overall Execution Flow**
|
||||
|
||||
.. figure:: usbdev.svg
|
||||
|
||||
**Host Protocol Stack Overall Execution Flow**
|
||||
|
||||
.. figure:: usbhost.svg
|
||||
|
||||
**Other Related Links**
|
||||
|
||||
- **Video Tutorial**: https://www.bilibili.com/cheese/play/ss707687201
|
||||
- **GitHub**: https://github.com/sakumisu/CherryUSB
|
||||
- **CherryUSB Theoretical Analysis and Application Practice - Hans Journal**: https://www.hanspub.org/journal/paperinformation?paperid=126903
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: Quick Start
|
||||
|
||||
quick_start/start
|
||||
quick_start/demo
|
||||
quick_start/transplant
|
||||
quick_start/rtthread
|
||||
quick_start/q&a
|
||||
quick_start/migration
|
||||
quick_start/share
|
||||
quick_start/opensource
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: USB Basic Knowledge
|
||||
|
||||
usb/usb2.0_basic
|
||||
usb/usb3.0_basic
|
||||
usb/usb_desc
|
||||
usb/usb_request
|
||||
usb/usb_enum
|
||||
usb/usb_ext
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: API Manual
|
||||
|
||||
api/api_device
|
||||
api/api_host
|
||||
api/api_port
|
||||
api/api_config
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: Class Guide
|
||||
|
||||
class/class_cdc
|
||||
class/class_hid
|
||||
class/class_msc
|
||||
class/class_audio
|
||||
class/class_video
|
||||
class/winusb
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: Examples
|
||||
|
||||
demo/usbd_cdc_acm
|
||||
demo/usbd_hid
|
||||
demo/usbd_msc
|
||||
demo/usbd_audiov1
|
||||
demo/usbd_audiov2
|
||||
demo/usbd_video
|
||||
demo/usbd_winusb
|
||||
demo/usbd_webusb
|
||||
demo/usbd_rndis
|
||||
demo/usbd_ecm
|
||||
demo/usbd_adb
|
||||
demo/usbd_mtp
|
||||
demo/usbh_serial
|
||||
demo/usbh_hid
|
||||
demo/usbh_msc
|
||||
demo/usbh_net
|
||||
demo/usbh_bluetooth
|
||||
demo/usbh_wifi
|
||||
demo/usbh_audio
|
||||
demo/usbh_video
|
||||
demo/usb_otg
|
||||
demo/usbd_vendor
|
||||
demo/usbh_vendor
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: USB IP Introduction
|
||||
|
||||
usbip/ohci
|
||||
usbip/ehci
|
||||
usbip/xhci
|
||||
usbip/chipidea
|
||||
usbip/dwc2
|
||||
usbip/musb
|
||||
usbip/fotg210
|
||||
usbip/cdns2
|
||||
usbip/cdns3
|
||||
usbip/dwc3
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: Tools Usage
|
||||
|
||||
tools/index
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: Version Information
|
||||
|
||||
version
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: Performance Showcase
|
||||
|
||||
show/index
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: Commercial Support
|
||||
|
||||
support/index
|
||||
313
docs/en/quick_start/demo.rst
Executable file
@@ -0,0 +1,313 @@
|
||||
Quick Verification Based on Existing Demos
|
||||
=============================================
|
||||
|
||||
Before learning USB or CherryUSB code, we need to quickly verify based on existing demos. Why? To enhance interest in USB and build confidence for the next steps. If demos can't run, or if you explore writing code by yourself, or read USB basic concepts first, you may find that you can't understand anything in the end - there are so many concepts that you simply can't remember them, thus losing interest in USB. Therefore, running demos first is very important. Below I will list the currently supported demo repositories.
|
||||
|
||||
Based on Bouffalolab Series Chips (Official SDK Support)
|
||||
--------------------------------------------------------------
|
||||
|
||||
.. list-table::
|
||||
:widths: 10 10 10
|
||||
:header-rows: 1
|
||||
|
||||
* - Repo url
|
||||
- USB IP
|
||||
- Version
|
||||
* - https://github.com/CherryUSB/cherryusb_bouffalolab
|
||||
- FOTG210
|
||||
- less than latest
|
||||
|
||||
Based on HPMicro Series Chips (Official SDK Support)
|
||||
-----------------------------------------------------
|
||||
|
||||
.. list-table::
|
||||
:widths: 10 10 10
|
||||
:header-rows: 1
|
||||
|
||||
* - Repo url
|
||||
- USB IP
|
||||
- Version
|
||||
* - https://github.com/CherryUSB/cherryusb_hpmicro
|
||||
- CHIPIDEA
|
||||
- less than latest
|
||||
|
||||
Based on esp32s2/s3/p4 Series Chips (Official SDK Support)
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
.. list-table::
|
||||
:widths: 10 10 10
|
||||
:header-rows: 1
|
||||
|
||||
* - Repo url
|
||||
- USB IP
|
||||
- Version
|
||||
* - https://github.com/CherryUSB/cherryusb_esp32
|
||||
- DWC2
|
||||
- less than latest
|
||||
|
||||
Default demo uses component library installation form, can be searched at https://components.espressif.com/ for cherryusb
|
||||
|
||||
ESP-Registry can refer to the official documentation, recommended to use vscode + esp-idf development environment.
|
||||
|
||||
- ctrl + shift + p select ESP-IDF welcome interface, then select Component manager
|
||||
|
||||
.. figure:: img/esp1.png
|
||||
|
||||
- Find cherryusb and install
|
||||
|
||||
.. figure:: img/esp2.png
|
||||
|
||||
- Open menuconfig, and open cherryusb configuration, select host or device mode according to actual situation
|
||||
|
||||
.. figure:: img/esp3.png
|
||||
.. figure:: img/esp4.png
|
||||
|
||||
Based on Phytium Series Chips (Official SDK Support)
|
||||
-------------------------------------------------------
|
||||
|
||||
.. list-table::
|
||||
:widths: 10 10 10
|
||||
:header-rows: 1
|
||||
|
||||
* - Repo url
|
||||
- USB IP
|
||||
- Version
|
||||
* - https://gitee.com/phytium_embedded/phytium-free-rtos-sdk
|
||||
- PUSB2/XHCI
|
||||
- equal to v1.4.0
|
||||
|
||||
Based on Essemi Series Chips (Official SDK Support)
|
||||
-------------------------------------------------------------
|
||||
|
||||
.. list-table::
|
||||
:widths: 10 10 10
|
||||
:header-rows: 1
|
||||
|
||||
* - Repo url
|
||||
- USB IP
|
||||
- Version
|
||||
* - https://github.com/CherryUSB/cherryusb_es32
|
||||
- MUSB
|
||||
- less than latest
|
||||
|
||||
Based on Artinchip Series Chips (Official SDK Support)
|
||||
-------------------------------------------------------------------
|
||||
|
||||
.. list-table::
|
||||
:widths: 10 10 10
|
||||
:header-rows: 1
|
||||
|
||||
* - Repo url
|
||||
- USB IP
|
||||
- Version
|
||||
* - https://gitee.com/artinchip/luban-lite
|
||||
- AIC/EHCI/OHCI
|
||||
- less than latest
|
||||
|
||||
Based on Kendryte canmv-k230 Chip (Official SDK Support)
|
||||
---------------------------------------------------------
|
||||
|
||||
.. list-table::
|
||||
:widths: 10 10 10
|
||||
:header-rows: 1
|
||||
|
||||
* - Repo url
|
||||
- USB IP
|
||||
- Version
|
||||
* - https://github.com/CherryUSB/k230_sdk
|
||||
- DWC2
|
||||
- less than latest
|
||||
|
||||
Based on NXP MCX Series Chips
|
||||
-------------------------------------
|
||||
|
||||
.. list-table::
|
||||
:widths: 10 10 10
|
||||
:header-rows: 1
|
||||
|
||||
* - Repo url
|
||||
- USB IP
|
||||
- Version
|
||||
* - https://github.com/CherryUSB/cherryusb_mcx https://github.com/RT-Thread/rt-thread/tree/master/bsp/nxp/mcx
|
||||
- CHIPIDEA/kinetis
|
||||
- less than latest
|
||||
|
||||
Based on SiFli SF32 Series Chips (Official SDK Support)
|
||||
--------------------------------------------------------
|
||||
|
||||
.. list-table::
|
||||
:widths: 10 10 10
|
||||
:header-rows: 1
|
||||
|
||||
* - Repo url
|
||||
- USB IP
|
||||
- Version
|
||||
* - https://github.com/OpenSiFli/SiFli-SDK
|
||||
- MUSB
|
||||
- less than latest
|
||||
|
||||
Based on RP2040/RP2035 Chips (Official SDK Support Coming Soon)
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
.. list-table::
|
||||
:widths: 10 10 10
|
||||
:header-rows: 1
|
||||
|
||||
* - Repo url
|
||||
- USB IP
|
||||
- Version
|
||||
* - https://github.com/CherryUSB/pico-examples https://github.com/CherryUSB/pico-sdk
|
||||
- RP2040
|
||||
- less than latest
|
||||
|
||||
Based on Actionstech Series Chips (Official SDK Support)
|
||||
-----------------------------------------------------------
|
||||
|
||||
Not opensource, please contact to Actionstech official
|
||||
|
||||
Based on ST Series Chips
|
||||
---------------------------
|
||||
|
||||
.. list-table::
|
||||
:widths: 10 10 10
|
||||
:header-rows: 1
|
||||
|
||||
* - Repo url
|
||||
- USB IP
|
||||
- Version
|
||||
* - https://github.com/CherryUSB/cherryusb_stm32
|
||||
- DWC2/FSDEV
|
||||
- less than latest
|
||||
|
||||
Default demo projects provided:
|
||||
|
||||
- F103 uses fsdev ip
|
||||
- F429 host and device use USB1, pins pb14/pb15, default device does not enable DMA mode
|
||||
- H7 device uses USB0, pins pa11/pa12, DMA mode not enabled. Host uses USB1, pins pb14/pb15, and needs nocache processing
|
||||
|
||||
Demo provides **stm32xxx.ioc** file, double click to open, click **Generate Code**.
|
||||
|
||||
.. caution:: After generation, please use git reset function to restore the overwritten `main.c` and `stm32xxx_it.c` files, prohibit being overwritten by cubemx.
|
||||
|
||||
Covers F1/F4/H7, other chips are basically similar and won't be repeated. Specific differences are:
|
||||
|
||||
- usb ip difference: F1 uses fsdev, F4/H7 use dwc2
|
||||
- dwc2 ip difference: USB0 (pins PA11/PA12) and USB1 (pins PB14/PB15), where USB1 defaults to full-speed, can connect external PHY to form high-speed host, and has DMA functionality
|
||||
- F4 has no cache, H7 has cache
|
||||
|
||||
If it's STM32F7/STM32H7 with cache functionality, you need to locate the ram used by usb to the no cache ram area. Example as follows
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
cpu_mpu_config(0, MPU_Normal_NonCache, 0x24070000, MPU_REGION_SIZE_64KB);
|
||||
|
||||
Corresponding sct script modification in Keil:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
LR_IROM1 0x08000000 0x00200000 { ; load region size_region
|
||||
ER_IROM1 0x08000000 0x00200000 { ; load address = execution address
|
||||
*.o (RESET, +First)
|
||||
*(InRoot$$Sections)
|
||||
.ANY (+RO)
|
||||
.ANY (+XO)
|
||||
}
|
||||
RW_IRAM2 0x24000000 0x00070000 { ; RW data
|
||||
.ANY (+RW +ZI)
|
||||
}
|
||||
USB_NOCACHERAM 0x24070000 0x00010000 { ; RW data
|
||||
*(.noncacheable)
|
||||
}
|
||||
}
|
||||
|
||||
USB Device Porting Points
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- Use **stm32cubemx** to create project, configure basic RCC, UART (used as log)
|
||||
|
||||
.. figure:: img/stm32_1.png
|
||||
.. figure:: img/stm32_2.png
|
||||
|
||||
- If using fsdev ip, check **USB**. If using dwc2 ip, check **USB_OTG_FS** or **USB_OTG_HS**. Enable USB interrupt. Other configurations are useless to us, no ST USB library will be used in the code.
|
||||
|
||||
.. figure:: img/stm32_3_1.png
|
||||
.. figure:: img/stm32_3_2.png
|
||||
|
||||
- Configure usb clock to 48M
|
||||
|
||||
.. figure:: img/stm32_4_1.png
|
||||
.. figure:: img/stm32_4_2.png
|
||||
|
||||
- Select project, here we choose keil, set stack and heap properly. If using msc, it's recommended to set them larger, then click **Generate Code**.
|
||||
|
||||
.. figure:: img/stm32_5.png
|
||||
|
||||
- Add CherryUSB required source code (**usbd_core.c**, **dwc2/usb_dc_dwc2.c** or **fsdev/usb_dc_fsdev.c**), as well as the class drivers you want to use. You can add corresponding class templates for convenient testing.
|
||||
|
||||
.. figure:: img/stm32_6.png
|
||||
|
||||
- Add necessary header files
|
||||
|
||||
.. figure:: img/stm32_7.png
|
||||
|
||||
- Copy **cherryusb_config_template.h**, place it in the `Core/Inc` directory, and name it `usb_config.h`
|
||||
|
||||
.. figure:: img/stm32_8.png
|
||||
|
||||
- If using fsdev ip, (starting from V1.5.0, need to add **fsdev/usb_glue_st.c**) implement the following macro definition in `usb_config.h`. The specific value varies for different chips:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
#define CONFIG_USBDEV_FSDEV_PMA_ACCESS 2
|
||||
|
||||
- Compiler recommends using **AC6**. Check **Microlib**, and implement **printf** for convenient log viewing later.
|
||||
|
||||
.. figure:: img/stm32_10.png
|
||||
.. figure:: img/stm32_11.png
|
||||
|
||||
.. note :: Starting from V1.5.0, the following two steps are no longer needed because they are already implemented in **fsdev/usb_glue_st.c** and **dwc2/usb_glue_st.c** files
|
||||
|
||||
- Copy the content of **HAL_PCD_MspInit** function in **xxx_msp.c** to **usb_dc_low_level_init** function, disable ST generated USB initialization
|
||||
|
||||
.. figure:: img/stm32_12.png
|
||||
.. figure:: img/stm32_14.png
|
||||
|
||||
- Call `USBD_IRQHandler` in interrupt function and pass in `busid`
|
||||
|
||||
.. figure:: img/stm32_13.png
|
||||
|
||||
- If the chip has cache, please refer to :ref:`usb_cache` chapter for cache modification
|
||||
|
||||
- Call template content initialization and fill in `busid` and USB IP's `reg base`. `busid` starts from 0 and cannot exceed `CONFIG_USBDEV_MAX_BUS`
|
||||
|
||||
.. figure:: img/stm32_15.png
|
||||
|
||||
USB Host Porting Points
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The first 6 steps are the same as device side. Note that host driver only supports HS port with DMA (pins PB14/PB15), so FS port (pins PA11/PA12) is not supported (what's the point of a host without DMA).
|
||||
|
||||
- Add CherryUSB required source code (**usbh_core.c**, **usbh_hub.c**, **usb_hc_dwc2.c**, **usb_glue_st.c** and adapter layer files in **osal** directory), as well as the class drivers you want to use, and you can add corresponding **usb host.c** for convenient testing.
|
||||
|
||||
.. figure:: img/stm32_16.png
|
||||
|
||||
- Compiler recommends using **AC6**. Check **Microlib**, and implement **printf** for convenient log viewing later.
|
||||
|
||||
.. figure:: img/stm32_10.png
|
||||
.. figure:: img/stm32_11.png
|
||||
|
||||
- Copy **cherryusb_config_template.h**, place it in the `Core/Inc` directory, and name it `usb_config.h`
|
||||
|
||||
.. note :: Starting from V1.5.0, the following two steps are no longer needed because they are already implemented in **fsdev/usb_glue_st.c** and **dwc2/usb_glue_st.c** files
|
||||
|
||||
- Copy the content of `HAL_HCD_MspInit` function in **xxx_msp.c** to `usb_hc_low_level_init` function, disable ST generated USB initialization
|
||||
- Call `USBH_IRQHandler` in interrupt function and pass in `busid`
|
||||
|
||||
.. figure:: img/stm32_19.png
|
||||
|
||||
- For linker script modifications, refer to :ref:`usbh_link_script` chapter
|
||||
- If the chip has cache, please refer to :ref:`usb_cache` chapter for cache modification
|
||||
- Call `usbh_initialize` and fill in `busid` and USB IP's `reg base` and `event_handler` (can be omitted as NULL). `busid` starts from 0 and cannot exceed `CONFIG_USBHOST_MAX_BUS`
|
||||
- Start thread
|
||||
|
||||
.. figure:: img/stm32_18.png
|
||||
0
docs/source/quick_start/img/env0.png → docs/en/quick_start/img/env0.png
Normal file → Executable file
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
0
docs/source/quick_start/img/env1.png → docs/en/quick_start/img/env1.png
Normal file → Executable file
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
0
docs/source/quick_start/img/env2.png → docs/en/quick_start/img/env2.png
Normal file → Executable file
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 65 KiB |
0
docs/source/quick_start/img/esp1.png → docs/en/quick_start/img/esp1.png
Normal file → Executable file
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
0
docs/source/quick_start/img/esp2.png → docs/en/quick_start/img/esp2.png
Normal file → Executable file
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 71 KiB |
0
docs/source/quick_start/img/esp3.png → docs/en/quick_start/img/esp3.png
Normal file → Executable file
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
0
docs/source/quick_start/img/esp4.png → docs/en/quick_start/img/esp4.png
Normal file → Executable file
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
0
docs/source/quick_start/img/question1.png → docs/en/quick_start/img/question1.png
Normal file → Executable file
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
0
docs/source/quick_start/img/question2.png → docs/en/quick_start/img/question2.png
Normal file → Executable file
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
0
docs/source/quick_start/img/stm32_1.png → docs/en/quick_start/img/stm32_1.png
Normal file → Executable file
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
0
docs/source/quick_start/img/stm32_10.png → docs/en/quick_start/img/stm32_10.png
Normal file → Executable file
|
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB |
0
docs/source/quick_start/img/stm32_11.png → docs/en/quick_start/img/stm32_11.png
Normal file → Executable file
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
0
docs/source/quick_start/img/stm32_12.png → docs/en/quick_start/img/stm32_12.png
Normal file → Executable file
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 78 KiB |
0
docs/source/quick_start/img/stm32_13.png → docs/en/quick_start/img/stm32_13.png
Normal file → Executable file
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
0
docs/source/quick_start/img/stm32_14.png → docs/en/quick_start/img/stm32_14.png
Normal file → Executable file
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
0
docs/source/quick_start/img/stm32_15.png → docs/en/quick_start/img/stm32_15.png
Normal file → Executable file
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
0
docs/source/quick_start/img/stm32_16.png → docs/en/quick_start/img/stm32_16.png
Normal file → Executable file
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
0
docs/source/quick_start/img/stm32_18.png → docs/en/quick_start/img/stm32_18.png
Normal file → Executable file
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
0
docs/source/quick_start/img/stm32_19.png → docs/en/quick_start/img/stm32_19.png
Normal file → Executable file
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
0
docs/source/quick_start/img/stm32_2.png → docs/en/quick_start/img/stm32_2.png
Normal file → Executable file
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
0
docs/source/quick_start/img/stm32_3_1.png → docs/en/quick_start/img/stm32_3_1.png
Normal file → Executable file
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
0
docs/source/quick_start/img/stm32_3_2.png → docs/en/quick_start/img/stm32_3_2.png
Normal file → Executable file
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
0
docs/source/quick_start/img/stm32_4_1.png → docs/en/quick_start/img/stm32_4_1.png
Normal file → Executable file
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
0
docs/source/quick_start/img/stm32_4_2.png → docs/en/quick_start/img/stm32_4_2.png
Normal file → Executable file
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 73 KiB |
0
docs/source/quick_start/img/stm32_5.png → docs/en/quick_start/img/stm32_5.png
Normal file → Executable file
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
0
docs/source/quick_start/img/stm32_6.png → docs/en/quick_start/img/stm32_6.png
Normal file → Executable file
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
0
docs/source/quick_start/img/stm32_7.png → docs/en/quick_start/img/stm32_7.png
Normal file → Executable file
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 8.6 KiB |
0
docs/source/quick_start/img/stm32_8.png → docs/en/quick_start/img/stm32_8.png
Normal file → Executable file
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
62
docs/en/quick_start/migration.rst
Executable file
@@ -0,0 +1,62 @@
|
||||
Partial Changes Migration Guide
|
||||
======================================
|
||||
|
||||
usbh_initialize
|
||||
------------------
|
||||
|
||||
usbh_initialize has added event_handler parameter starting from v1.6.0. Usually not needed, can pass NULL.
|
||||
|
||||
dwc2 glue st
|
||||
----------------
|
||||
|
||||
Starting from v1.5.0, dwc2 glue file has built-in low-level initialization, such as `usb_dc_low_level_init`, which depends on `HAL_PCD_MspInit` and `HAL_HCD_MspInit`. Must use stm32cubemx generation. Third-party platforms do not guarantee having these function implementations, check by yourself.
|
||||
|
||||
|
||||
dwc2 glue
|
||||
----------------
|
||||
|
||||
Starting from v1.5.1, dwc2 adds `struct dwc2_user_params` for implementing different configurations for multiple dwc2 ports. It replaces `usbd_get_dwc2_gccfg_conf` and `usbh_get_dwc2_hccfg_conf` functions,
|
||||
and adds `dwc2_get_user_params` function implementation, example as follows:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
#ifndef CONFIG_USB_DWC2_CUSTOM_PARAM
|
||||
void dwc2_get_user_params(uint32_t reg_base, struct dwc2_user_params *params)
|
||||
{
|
||||
memcpy(params, ¶m_common, sizeof(struct dwc2_user_params));
|
||||
#ifdef CONFIG_USB_DWC2_CUSTOM_FIFO
|
||||
struct usb_dwc2_user_fifo_config s_dwc2_fifo_config;
|
||||
|
||||
dwc2_get_user_fifo_config(reg_base, &s_dwc2_fifo_config);
|
||||
|
||||
params->device_rx_fifo_size = s_dwc2_fifo_config.device_rx_fifo_size;
|
||||
for (uint8_t i = 0; i < MAX_EPS_CHANNELS; i++) {
|
||||
params->device_tx_fifo_size[i] = s_dwc2_fifo_config.device_tx_fifo_size[i];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
host serial
|
||||
----------------
|
||||
|
||||
Starting from v1.6.0, host adds host serial framework for unifying all serial-like devices. The following APIs need to be replaced with new serial APIs:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbh_xxx_set_line_coding(struct usbh_xxx *xxx_class, struct cdc_line_coding *line_coding);
|
||||
int usbh_xxx_get_line_coding(struct usbh_xxx *xxx_class, struct cdc_line_coding *line_coding);
|
||||
int usbh_xxx_set_line_state(struct usbh_xxx *xxx_class, bool dtr, bool rts);
|
||||
|
||||
int usbh_xxx_bulk_in_transfer(struct usbh_xxx *xxx_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
|
||||
int usbh_xxx_bulk_out_transfer(struct usbh_xxx *xxx_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
|
||||
|
||||
Replace with:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
struct usbh_serial *usbh_serial_open(const char *devname, uint32_t open_flags);
|
||||
int usbh_serial_close(struct usbh_serial *serial);
|
||||
int usbh_serial_control(struct usbh_serial *serial, int cmd, void *arg);
|
||||
int usbh_serial_write(struct usbh_serial *serial, const void *buffer, uint32_t buflen);
|
||||
int usbh_serial_read(struct usbh_serial *serial, void *buffer, uint32_t buflen);
|
||||