diff options
| author | sakumisu <[email protected]> | 2022-03-08 12:39:41 +0800 |
|---|---|---|
| committer | sakumisu <[email protected]> | 2022-03-08 12:39:41 +0800 |
| commit | b8d1fd6b658a3673adc7fb46284eae0e17b4c9bb (patch) | |
| tree | 55a28ab93ed07523f2955d83082714a94dfcbd27 /docs/source | |
| parent | 5772d29f14eef3462982c3a71a7d20eacc2648fa (diff) | |
update doc structure,hosting with readdoc
Diffstat (limited to 'docs/source')
62 files changed, 1261 insertions, 0 deletions
diff --git a/docs/source/api/api_common.rst b/docs/source/api/api_common.rst new file mode 100644 index 00000000..6f743643 --- /dev/null +++ b/docs/source/api/api_common.rst @@ -0,0 +1,2 @@ +其他 +========================= diff --git a/docs/source/api/api_device.rst b/docs/source/api/api_device.rst new file mode 100644 index 00000000..71e10514 --- /dev/null +++ b/docs/source/api/api_device.rst @@ -0,0 +1,497 @@ +设备协议栈 +========================= + +CORE +----------------- + +端点结构体 +"""""""""""""""""""""""""""""""""""" + +端点结构体主要用于注册不同端点地址的中断完成回调函数。 + +.. code-block:: C + + typedef struct usbd_endpoint { + usb_slist_t list; + uint8_t ep_addr; + usbd_endpoint_callback ep_cb; + } usbd_endpoint_t; + +- **list** 端点的链表节点 +- **ep_addr** 端点地址(带方向) +- **ep_cb** 端点中断回调函数 + +接口结构体 +"""""""""""""""""""""""""""""""""""" + +接口结构体主要用于注册不同类设备除了标准设备请求外的其他请求,包括类设备请求、厂商设备请求和自定义设备请求。以及协议栈中的相关通知回调函数。 + +.. code-block:: C + + typedef struct usbd_interface { + usb_slist_t list; + /** Handler for USB Class specific commands*/ + usbd_request_handler class_handler; + /** Handler for USB Vendor specific commands */ + usbd_request_handler vendor_handler; + /** Handler for USB custom specific commands */ + usbd_request_handler custom_handler; + /** Handler for USB event notify commands */ + usbd_notify_handler notify_handler; + uint8_t intf_num; + usb_slist_t ep_list; + } usbd_interface_t; + +- **list** 接口的链表节点 +- **class_handler** class setup 请求回调函数 +- **vendor_handler** vendor setup 请求回调函数 +- **custom_handler** custom setup 请求回调函数 +- **notify_handler** 中断标志、协议栈相关状态回调函数 +- **intf_num** 当前接口偏移 +- **ep_list** 端点的链表节点 + +类结构体 +"""""""""""""""""""""""""""""""""""" + +类结构体主要用于挂载接口链表。后期可能会删除,因为这个部分跟接口其实是有关系的。 + +.. code-block:: C + + typedef struct usbd_class { + usb_slist_t list; + const char *name; + usb_slist_t intf_list; + } usbd_class_t; + +- **list** 类的链表节点 +- **name** 类的名称 +- **intf_list** 接口的链表节点 + +usbd_event_notify_handler +"""""""""""""""""""""""""""""""""""" + +``usbd_event_notify_handler`` 是 USB 中断中的核心,用于处理不同的中断标志。包括复位、端点0 IN/OUT/SETUP、其他端点 IN/OUT 、SUSPEND、RESUME、SOF 中断等等。用户需要在 porting 接口中的 USB中断中调用该接口。 + +.. code-block:: C + + void usbd_event_notify_handler(uint8_t event, void *arg); + +- **event** 中断事件 +- **arg** 端点号 + +其中 ``event`` 有如下类型: + +.. code-block:: C + + enum usbd_event_type { + /** USB error reported by the controller */ + USBD_EVENT_ERROR, + /** USB reset */ + USBD_EVENT_RESET, + /** Start of Frame received */ + USBD_EVENT_SOF, + /** USB connection established, hardware enumeration is completed */ + USBD_EVENT_CONNECTED, + /** USB configuration done */ + USBD_EVENT_CONFIGURED, + /** USB connection suspended by the HOST */ + USBD_EVENT_SUSPEND, + /** USB connection lost */ + USBD_EVENT_DISCONNECTED, + /** USB connection resumed by the HOST */ + USBD_EVENT_RESUME, + + /** USB interface selected */ + USBD_EVENT_SET_INTERFACE, + /** USB interface selected */ + USBD_EVENT_SET_REMOTE_WAKEUP, + /** USB interface selected */ + USBD_EVENT_CLEAR_REMOTE_WAKEUP, + /** Set Feature ENDPOINT_HALT received */ + USBD_EVENT_SET_HALT, + /** Clear Feature ENDPOINT_HALT received */ + USBD_EVENT_CLEAR_HALT, + /** setup packet received */ + USBD_EVENT_SETUP_NOTIFY, + /** ep0 in packet received */ + USBD_EVENT_EP0_IN_NOTIFY, + /** ep0 out packet received */ + USBD_EVENT_EP0_OUT_NOTIFY, + /** ep in packet except ep0 received */ + USBD_EVENT_EP_IN_NOTIFY, + /** ep out packet except ep0 received */ + USBD_EVENT_EP_OUT_NOTIFY, + /** Initial USB connection status */ + USBD_EVENT_UNKNOWN + }; + +usbd_desc_register +"""""""""""""""""""""""""""""""""""" + +``usbd_desc_register`` 用来注册 USB 描述符,描述符种类包括:设备描述符、配置描述符(包含配置描述符、接口描述符、class 类描述符、端点描述符)、字符串描述符、设备限定描述符。 + +.. code-block:: C + + void usbd_desc_register(const uint8_t *desc); + +- **desc** 描述符的句柄 + +usbd_msosv1_desc_register +"""""""""""""""""""""""""""""""""""" + +``usbd_msosv1_desc_register`` 用来注册一个 WINUSB 1.0 描述符。 + +.. code-block:: C + + void usbd_msosv1_desc_register(struct usb_msosv1_descriptor *desc); + +- **desc** 描述符句柄 + +usbd_msosv2_desc_register +"""""""""""""""""""""""""""""""""""" + +``usbd_msosv2_desc_register`` 用来注册一个 WINUSB 2.0 描述符。 + +.. code-block:: C + + void usbd_msosv2_desc_register(struct usb_msosv2_descriptor *desc); + +- **desc** 描述符句柄 + +usbd_bos_desc_register +"""""""""""""""""""""""""""""""""""" + +``usbd_bos_desc_register`` 用来注册一个 BOS 描述符, USB 2.1 版本以上必须注册。 + +.. code-block:: C + + void usbd_bos_desc_register(struct usb_bos_descriptor *desc); + +- **desc** 描述符句柄 + +usbd_class_register +"""""""""""""""""""""""""""""""""""" + +``usbd_class_register`` 用来注册一个 class,该 class 中的接口链表成员,用于后续挂载多个接口。 + +.. code-block:: C + + void usbd_class_register(usbd_class_t *devclass); + +- **devclass** USB 设备类的句柄 + +usbd_class_add_interface +"""""""""""""""""""""""""""""""""""" + +``usbd_class_add_interface`` 用来给 USB 设备类增加接口,并将接口信息挂载在类的链表上。 + +.. code-block:: C + + void usbd_class_add_interface(usbd_class_t *devclass, usbd_interface_t *intf); + +- **devclass** USB 设备类的句柄 +- **intf** USB 设备接口的句柄 + +**usbd_interface_add_endpoint** +"""""""""""""""""""""""""""""""""""" + +``usbd_interface_add_endpoint`` 用来给 USB 接口增加端点,并将端点信息挂载在接口的链表上。 + +.. code-block:: C + + void usbd_interface_add_endpoint(usbd_interface_t *intf, usbd_endpoint_t *ep); + + +- **intf** USB 设备接口的句柄 +- **ep** USB 设备端点的句柄 + +**usb_device_is_configured** +"""""""""""""""""""""""""""""""""""" + +``usb_device_is_configured`` 用来检查 USB 设备是否被配置(枚举)。 + +.. code-block:: C + + bool usb_device_is_configured(void); + +- **return** 配置状态, 0 表示未配置, 1 表示配置成功 + +CDC ACM +----------------- + +usbd_cdc_add_acm_interface +"""""""""""""""""""""""""""""""""""" + +``usbd_cdc_add_acm_interface`` 用来给 USB CDC ACM 类添加接口,并实现该接口相关的函数: + +- ``cdc_acm_class_request_handler`` 用来处理 USB CDC ACM 类 Setup 请求。 +- ``cdc_notify_handler`` 用来处理 USB CDC 其他中断回调函数。 + +.. code-block:: C + + void usbd_cdc_add_acm_interface(usbd_class_t *devclass, usbd_interface_t *intf); + +- **devclass** 类的句柄 +- **intf** 接口句柄 + +usbd_cdc_acm_set_line_coding +"""""""""""""""""""""""""""""""""""" + +``usbd_cdc_acm_set_line_coding`` 用来对串口进行配置,如果仅使用 USB 而不用 串口,该接口不用用户实现,使用默认。 + +.. code-block:: C + + void usbd_cdc_acm_set_line_coding(uint32_t baudrate, uint8_t databits, uint8_t parity, uint8_t stopbits); + +- **baudrate** 波特率 +- **databits** 数据位 +- **parity** 校验位 +- **stopbits** 停止位 + +usbd_cdc_acm_set_dtr +"""""""""""""""""""""""""""""""""""" + +``usbd_cdc_acm_set_dtr`` 用来控制串口 DTR 。如果仅使用 USB 而不用 串口,该接口不用用户实现,使用默认。 + +.. code-block:: C + + void usbd_cdc_acm_set_dtr(bool dtr); + +- **dtr** dtr 为1表示拉低电平,为0表示拉高电平 + +usbd_cdc_acm_set_rts +"""""""""""""""""""""""""""""""""""" + +``usbd_cdc_acm_set_rts`` 用来控制串口 RTS 。如果仅使用 USB 而不用 串口,该接口不用用户实现,使用默认。 + +.. code-block:: C + + void usbd_cdc_acm_set_rts(bool rts); + +- **rts** rts 为1表示拉低电平,为0表示拉高电平 + +HID +----------------- + +usbd_hid_add_interface +"""""""""""""""""""""""""""""""""""" + +``usbd_hid_add_interface`` 用来给 USB HID 类添加接口,并实现该接口相关的函数: + +- ``hid_class_request_handler`` 用来处理 USB HID 类的 Setup 请求。 +- ``hid_custom_request_handler`` 用来处理 USB HID 获取报告描述符请求。 +- ``hid_notify_handler`` 用来处理 USB HID 其他中断回调函数。 + +.. code-block:: C + + void usbd_hid_add_interface(usbd_class_t *devclass, usbd_interface_t *intf); + +- **devclass** 类的句柄 +- **intf** 接口句柄 + +usbd_hid_report_descriptor_register +"""""""""""""""""""""""""""""""""""""""""""" + +``usbd_hid_report_descriptor_register`` 用来注册 hid 报告描述符。 + +.. code-block:: C + + void usbd_hid_report_descriptor_register(uint8_t intf_num, const uint8_t *desc, uint32_t desc_len); + +- **intf_num** 当前 hid 报告描述符所在接口偏移 +- **desc** 报告描述符 +- **desc_len** 报告描述符长度 + +usbd_hid_set_request_callback +"""""""""""""""""""""""""""""""""""" + +``usbd_hid_set_request_callback`` 用来注册 hid 类请求命令的回调函数。 + +.. code-block:: C + + void usbd_hid_set_request_callback( uint8_t intf_num, + uint8_t (*get_report_callback)(uint8_t report_id, uint8_t report_type), + void (*set_report_callback)(uint8_t report_id, uint8_t report_type, uint8_t *report, uint8_t report_len), + uint8_t (*get_idle_callback)(uint8_t report_id), + void (*set_idle_callback)(uint8_t report_id, uint8_t duration), + void (*set_protocol_callback)(uint8_t protocol), + uint8_t (*get_protocol_callback)(void)); + +- **intf_num** 当前 hid 报告描述符所在接口偏移 +- **get_report_callback** get report命令处理回调函数 +- **set_report_callback** set report命令处理回调函数 +- **get_idle_callback** get idle命令处理回调函数 +- **set_idle_callback** set idle命令处理回调函数 +- **set_protocol_callback** set protocol命令处理回调函数 +- **get_protocol_callback** get protocol命令处理回调函数 + +MSC +----------------- + +usbd_msc_class_init +"""""""""""""""""""""""""""""""""""" +``usbd_msc_class_init`` 用来给 MSC 类添加接口,并实现该接口相关函数,并且注册端点回调函数。(因为 msc bot 协议是固定的,所以不需要用于实现,因此端点回调函数自然不需要用户实现)。 + +- ``msc_storage_class_request_handler`` 用于处理 USB MSC Setup 中断请求。 +- ``msc_storage_notify_handler`` 用于实现 USB MSC 其他中断回调函数。 + +- ``mass_storage_bulk_out`` 用于处理 USB MSC 端点 out 中断。 +- ``mass_storage_bulk_in`` 用于处理 USB MSC 端点 in 中断。 + +.. code-block:: C + + void usbd_msc_class_init(uint8_t out_ep, uint8_t in_ep); + +- **out_ep** out 端点地址 +- **in_ep** in 端点地址 + +usbd_msc_get_cap +"""""""""""""""""""""""""""""""""""" + +``usbd_msc_get_cap`` 用来获取存储器的 lun、扇区个数和每个扇区大小。用户必须实现该函数。 + +.. code-block:: C + + void usbd_msc_get_cap(uint8_t lun, uint32_t *block_num, uint16_t *block_size); + +- **lun** 存储逻辑单元,暂时无用,默认支持一个 +- **block_num** 存储扇区个数 +- **block_size** 存储扇区大小 + +usbd_msc_sector_read +"""""""""""""""""""""""""""""""""""" + +``usbd_msc_sector_read`` 用来对存储器某个扇区开始的地址进行数据读取。用户必须实现该函数。 + +.. code-block:: C + + int usbd_msc_sector_read(uint32_t sector, uint8_t *buffer, uint32_t length); + +- **sector** 扇区偏移 +- **buffer** 存储读取的数据的指针 +- **length** 读取长度 + + +usbd_msc_sector_write +"""""""""""""""""""""""""""""""""""" + +``usbd_msc_sector_write`` 用来对存储器某个扇区开始写入数据。用户必须实现该函数。 + +.. code-block:: C + + int usbd_msc_sector_write(uint32_t sector, uint8_t *buffer, uint32_t length); + +- **sector** 扇区偏移 +- **buffer** 写入数据指针 +- **length** 写入长度 + +UAC +----------------- + +usbd_audio_add_interface +"""""""""""""""""""""""""""""""""""" +``usbd_audio_add_interface`` 用来给 USB Audio 类添加接口,并实现该接口相关的函数: + +- ``audio_class_request_handler`` 用于处理 USB Audio Setup 中断请求。 +- ``audio_notify_handler`` 用于实现 USB Audio 其他中断回调函数。 + +.. code-block:: C + + void usbd_audio_add_interface(usbd_class_t *devclass, usbd_interface_t *intf); + +- **class** 类的句柄 +- **intf** 接口句柄 + +usbd_audio_set_mute +"""""""""""""""""""""""""""""""""""" + +``usbd_audio_set_mute`` 用来设置静音。 + +.. code-block:: C + + void usbd_audio_set_mute(uint8_t mute); + +- **mute** 为1 表示静音,0相反 + +usbd_audio_set_volume +"""""""""""""""""""""""""""""""""""" + +``usbd_audio_set_volume`` 用来设置音量。 + +.. code-block:: C + + void usbd_audio_set_volume(uint8_t vol); + +- **vol** 音量,从 0-100 + +usbd_audio_set_interface_callback +"""""""""""""""""""""""""""""""""""" + +``usbd_audio_set_interface_callback`` 用来开关音频数据传输。 + +.. code-block:: C + + void usbd_audio_set_interface_callback(uint8_t value); + +- **value** 为1 表示开启 stream 传输,为0 相反 + +UVC +----------------- + +usbd_video_add_interface +"""""""""""""""""""""""""""""""""""" +``usbd_video_add_interface`` 用来给 USB Video 类添加接口,并实现该接口相关的函数: + +- ``video_class_request_handler`` 用于处理 USB Video Setup 中断请求。 +- ``video_notify_handler`` 用于实现 USB Video 其他中断回调函数。 + +.. code-block:: C + + void usbd_video_add_interface(usbd_class_t *devclass, usbd_interface_t *intf); + +- **class** 类的句柄 +- **intf** 接口句柄 + +usbd_video_probe_and_commit_controls_init +"""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +``usbd_video_probe_and_commit_controls_init`` 用来开关视频数据传输。 + +.. code-block:: C + + void usbd_video_probe_and_commit_controls_init(uint32_t dwFrameInterval, uint32_t dwMaxVideoFrameSize, uint32_t dwMaxPayloadTransferSize); + +- **value** 为1 表示开启 stream 传输,为0 相反 + +usbd_video_mjpeg_payload_fill +"""""""""""""""""""""""""""""""""""" + +``usbd_video_mjpeg_payload_fill`` 用来填充 mjpeg 到新的 buffer中,其中会对 mjpeg 数据按帧进行切分,切分大小由 ``dwMaxPayloadTransferSize`` 控制,并添加头部信息,当前头部字节数为 2。头部信息见 ``struct video_mjpeg_payload_header`` + +.. code-block:: C + + uint32_t usbd_video_mjpeg_payload_fill(uint8_t *input, uint32_t input_len, uint8_t *output, uint32_t *out_len); + +- **input** mjpeg 格式的数据包,从 FFD8~FFD9结束 +- **input_len** mjpeg数据包大小 +- **output** 输出缓冲区 +- **out_len** 输出实际要发送的长度大小 +- **return** 返回 usb 按照 ``dwMaxPayloadTransferSize`` 大小要发多少帧 + +usbd_video_mjpeg_payload_header_toggle +"""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +``usbd_video_mjpeg_payload_header_toggle`` 用来对每一帧图像数据要发送时进行翻转,并保持到一帧图像数据发送完成。 + +.. code-block:: C + + void usbd_video_mjpeg_payload_header_toggle(uint8_t *output, uint32_t packets); + +- **output** 要翻转的 usb 缓冲区,该缓冲区是 ``usbd_video_mjpeg_payload_fill`` 中的 ``output`` +- **packets** USB 发送的帧个数 + +DFU +----------------- + +PORTING +-----------------
\ No newline at end of file diff --git a/docs/source/api/api_host.rst b/docs/source/api/api_host.rst new file mode 100644 index 00000000..fdee2c18 --- /dev/null +++ b/docs/source/api/api_host.rst @@ -0,0 +1,161 @@ +主机协议栈 +========================= + +CORE +----------------- + +CLASS 驱动信息结构体 +"""""""""""""""""""""""""""""""""""" + +.. code-block:: C + + struct usbh_class_info { + uint8_t class; /* Base device class code */ + uint8_t subclass; /* Sub-class, depends on base class. Eg. */ + uint8_t protocol; /* Protocol, depends on base class. Eg. */ + uint16_t vid; /* Vendor ID (for vendor/product specific devices) */ + uint16_t pid; /* Product ID (for vendor/product specific devices) */ + const struct usbh_class_driver *class_driver; + }; + +端点结构体 +"""""""""""""""""""""""""""""""""""" + +.. code-block:: C + + typedef struct usbh_endpoint { + struct usb_endpoint_descriptor ep_desc; + } usbh_endpoint_t; + +接口结构体 +"""""""""""""""""""""""""""""""""""" + +.. code-block:: C + + typedef struct usbh_interface { + struct usb_interface_descriptor intf_desc; + struct usbh_endpoint ep[CONFIG_USBHOST_EP_NUM]; + char devname[CONFIG_USBHOST_DEV_NAMELEN]; + struct usbh_class_driver *class_driver; + void *priv; + } usbh_interface_t; + + +配置结构体 +"""""""""""""""""""""""""""""""""""" + +.. code-block:: C + + typedef struct usbh_configuration { + struct usb_configuration_descriptor config_desc; + struct usbh_interface intf[CONFIG_USBHOST_INTF_NUM]; + } usbh_configuration_t; + +hubport 结构体 +"""""""""""""""""""""""""""""""""""" + +.. code-block:: C + + typedef struct usbh_hubport { + bool connected; /* True: device connected; false: disconnected */ + bool port_change; /* True: port changed; false: port do not change */ + uint8_t port; /* Hub port index */ + uint8_t dev_addr; /* device address */ + uint8_t speed; /* device speed */ + usbh_epinfo_t ep0; /* control ep info */ + struct usb_device_descriptor device_desc; + struct usbh_configuration config; + #if 0 + uint8_t* config_desc; + #endif + struct usb_setup_packet *setup; + struct usbh_hub *parent; /*if NULL, is roothub*/ + } usbh_hubport_t; + +hub 结构体 +"""""""""""""""""""""""""""""""""""" + +.. code-block:: C + + typedef struct usbh_hub { + usb_slist_t list; + uint8_t index; /* Hub index */ + uint8_t nports; /* Hub port number */ + uint8_t dev_addr; /* Hub device address */ + usbh_epinfo_t intin; + uint8_t *int_buffer; + struct hub_port_status *port_status; + struct usb_hub_descriptor hub_desc; + struct usbh_hubport child[CONFIG_USBHOST_EHPORTS]; + struct usbh_hubport *parent; /* Parent hub port */ + struct usb_work work; + } usbh_hub_t; + +usbh_event_notify_handler +"""""""""""""""""""""""""""""""""""" + +``usbh_event_notify_handler`` 是 USB 中断中的核心,用于处理不同的中断标志。包括复位、端点0 IN/OUT/SETUP、其他端点 IN/OUT 、SUSPEND、RESUME、SOF 中断等等。用于需要在 porting 接口中的 USB中断中调用该接口。 + +.. code-block:: C + + void usbh_event_notify_handler(uint8_t event, uint8_t rhport); + +- **event** 中断事件 +- **rhport** roothub 端口号 + +其中 ``event`` 有如下类型: + +.. code-block:: C + + enum usbh_event_type { + USBH_EVENT_ATTACHED, + USBH_EVENT_REMOVED, + }; + +usbh_initialize +"""""""""""""""""""""""""""""""""""" + +``usbh_initialize`` 用来初始化 usb 主机协议栈,包括:创建插拔检测用的信号量和枚举线程、高低工作队列、初始化 roothub端点0 配置,初始化 usb 主机控制器。 + +.. code-block:: C + + int usbh_initialize(void); + +usbh_find_class_instance +"""""""""""""""""""""""""""""""""""" + +``usbh_find_class_instance`` 根据注册的 class 名称查找对应的 class 结构体句柄。 + +.. code-block:: C + + void *usbh_find_class_instance(const char *devname); + +- **devname** class 名称 +- **return** class 结构体句柄 + +lsusb +"""""""""""""""""""""""""""""""""""" + +``lsusb`` 用来查看和操作 hub 上的设备信息。需要借助 shell 插件使用。 + +.. code-block:: C + + int lsusb(int argc, char **argv); + +CDC ACM +----------------- + +HID +----------------- + +MSC +----------------- + +UAC +----------------- + +UVC +----------------- + +PORTING +-----------------
\ No newline at end of file diff --git a/docs/source/class/class_audio.rst b/docs/source/class/class_audio.rst new file mode 100644 index 00000000..a9f00098 --- /dev/null +++ b/docs/source/class/class_audio.rst @@ -0,0 +1,2 @@ +UAC +========================= diff --git a/docs/source/class/class_cdc.rst b/docs/source/class/class_cdc.rst new file mode 100644 index 00000000..1ee9a86a --- /dev/null +++ b/docs/source/class/class_cdc.rst @@ -0,0 +1,2 @@ +CDC +========================= diff --git a/docs/source/class/class_hid.rst b/docs/source/class/class_hid.rst new file mode 100644 index 00000000..21b85cf2 --- /dev/null +++ b/docs/source/class/class_hid.rst @@ -0,0 +1,2 @@ +HID +========================= diff --git a/docs/source/class/class_msc.rst b/docs/source/class/class_msc.rst new file mode 100644 index 00000000..ab230e70 --- /dev/null +++ b/docs/source/class/class_msc.rst @@ -0,0 +1,2 @@ +MSC +========================= diff --git a/docs/source/class/class_video.rst b/docs/source/class/class_video.rst new file mode 100644 index 00000000..7a1458ce --- /dev/null +++ b/docs/source/class/class_video.rst @@ -0,0 +1,2 @@ +UVC +========================= diff --git a/docs/source/class/winusb.rst b/docs/source/class/winusb.rst new file mode 100644 index 00000000..8c74d3b7 --- /dev/null +++ b/docs/source/class/winusb.rst @@ -0,0 +1,2 @@ +WINUSB +========================= diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 00000000..968d8ad1 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,37 @@ +# Configuration file for the Sphinx documentation builder. + +# -- Project information + +project = 'CherryUSB' +copyright = '2022, sakumisu' +author = 'sakumisu' + +release = '0.1' +version = '0.1.0' + +# -- General configuration + +extensions = [ + 'sphinx.ext.duration', + 'sphinx.ext.doctest', + 'sphinx.ext.autodoc', + 'sphinx.ext.autosummary', + 'sphinx.ext.intersphinx', + 'recommonmark', + 'sphinx_markdown_tables' +] + +intersphinx_mapping = { + 'python': ('https://docs.python.org/3/', None), + 'sphinx': ('https://www.sphinx-doc.org/en/master/', None), +} +intersphinx_disabled_domains = ['std'] + +templates_path = ['_templates'] + +# -- Options for HTML output + +html_theme = 'sphinx_rtd_theme' + +# -- Options for EPUB output +epub_show_urls = 'footnote' diff --git a/docs/source/demo/daplink.rst b/docs/source/demo/daplink.rst new file mode 100644 index 00000000..7fd292cb --- /dev/null +++ b/docs/source/demo/daplink.rst @@ -0,0 +1,2 @@ +DAPLINK V2.0调试器 +========================= diff --git a/docs/source/demo/mouse_keyboard.rst b/docs/source/demo/mouse_keyboard.rst new file mode 100644 index 00000000..11a1f22f --- /dev/null +++ b/docs/source/demo/mouse_keyboard.rst @@ -0,0 +1,2 @@ +键盘与鼠标 +========================= diff --git a/docs/source/demo/msc_boot.rst b/docs/source/demo/msc_boot.rst new file mode 100644 index 00000000..6e15bfc3 --- /dev/null +++ b/docs/source/demo/msc_boot.rst @@ -0,0 +1,2 @@ +U盘制作 BootLoader +========================= diff --git a/docs/source/demo/speaker_mic.rst b/docs/source/demo/speaker_mic.rst new file mode 100644 index 00000000..cb366ff0 --- /dev/null +++ b/docs/source/demo/speaker_mic.rst @@ -0,0 +1,2 @@ +USB 双通道扬声器和麦克风 +=========================== diff --git a/docs/source/demo/usb2uart.rst b/docs/source/demo/usb2uart.rst new file mode 100644 index 00000000..109f78dd --- /dev/null +++ b/docs/source/demo/usb2uart.rst @@ -0,0 +1,2 @@ +USB 转串口 +========================= diff --git a/docs/source/demo/video.rst b/docs/source/demo/video.rst new file mode 100644 index 00000000..e89ec6f9 --- /dev/null +++ b/docs/source/demo/video.rst @@ -0,0 +1,2 @@ +USB 摄像头 +=========================== diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 00000000..36890796 --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,62 @@ +.. CherryUSB 使用指南 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 使用指南 +====================================================== + +CherryUSB 是一个小而美的、可移植性高的、用于嵌入式系统的 USB 主从协议栈。 + +.. toctree:: + :maxdepth: 3 + :caption: 快速入门 + + quick_start/bl702 + quick_start/stm32f429 + quick_start/ch32v307 + quick_start/rt-thread/rt-thread_zh + +.. toctree:: + :maxdepth: 1 + :caption: USB 基本知识点 + + usb/usb_basic + usb/usb_desc + usb/usb_request + usb/usb_enum +.. toctree:: + :maxdepth: 1 + :caption: API 手册 + + api/api_device + api/api_host + api/api_common + +.. toctree:: + :maxdepth: 1 + :caption: Class 指南 + + class/class_cdc + class/class_hid + class/class_msc + class/class_audio + class/class_video + class/winusb + +.. toctree:: + :maxdepth: 1 + :caption: 综合例程 + + demo/usb2uart + demo/mouse_keyboard + demo/msc_boot + demo/video + demo/speaker_mic + demo/daplink + +.. toctree:: + :maxdepth: 1 + :caption: Porting 说明 + + porting diff --git a/docs/source/porting.rst b/docs/source/porting.rst new file mode 100644 index 00000000..869fddcd --- /dev/null +++ b/docs/source/porting.rst @@ -0,0 +1,2 @@ +Porting 编写说明 +==============================
\ No newline at end of file diff --git a/docs/source/quick_start/bl702.rst b/docs/source/quick_start/bl702.rst new file mode 100644 index 00000000..a459efe5 --- /dev/null +++ b/docs/source/quick_start/bl702.rst @@ -0,0 +1,2 @@ +基于 BL702 开发指南 +========================= diff --git a/docs/source/quick_start/ch32v307.rst b/docs/source/quick_start/ch32v307.rst new file mode 100644 index 00000000..3df76b1e --- /dev/null +++ b/docs/source/quick_start/ch32v307.rst @@ -0,0 +1,2 @@ +基于 CH32V307 开发指南 +========================= diff --git a/docs/source/quick_start/rt-thread/img/1.png b/docs/source/quick_start/rt-thread/img/1.png Binary files differnew file mode 100644 index 00000000..5176a02c --- /dev/null +++ b/docs/source/quick_start/rt-thread/img/1.png diff --git a/docs/source/quick_start/rt-thread/img/2.png b/docs/source/quick_start/rt-thread/img/2.png Binary files differnew file mode 100644 index 00000000..29d30734 --- /dev/null +++ b/docs/source/quick_start/rt-thread/img/2.png diff --git a/docs/source/quick_start/rt-thread/img/3.png b/docs/source/quick_start/rt-thread/img/3.png Binary files differnew file mode 100644 index 00000000..82bb35ff --- /dev/null +++ b/docs/source/quick_start/rt-thread/img/3.png diff --git a/docs/source/quick_start/rt-thread/img/rtt_cdc_demo.png b/docs/source/quick_start/rt-thread/img/rtt_cdc_demo.png Binary files differnew file mode 100644 index 00000000..861669e1 --- /dev/null +++ b/docs/source/quick_start/rt-thread/img/rtt_cdc_demo.png diff --git a/docs/source/quick_start/rt-thread/img/rtt_libc.png b/docs/source/quick_start/rt-thread/img/rtt_libc.png Binary files differnew file mode 100644 index 00000000..7fd5f00c --- /dev/null +++ b/docs/source/quick_start/rt-thread/img/rtt_libc.png diff --git a/docs/source/quick_start/rt-thread/img/rtt_menuconfig1.png b/docs/source/quick_start/rt-thread/img/rtt_menuconfig1.png Binary files differnew file mode 100644 index 00000000..24caa9c7 --- /dev/null +++ b/docs/source/quick_start/rt-thread/img/rtt_menuconfig1.png diff --git a/docs/source/quick_start/rt-thread/img/rtt_menuconfig2.png b/docs/source/quick_start/rt-thread/img/rtt_menuconfig2.png Binary files differnew file mode 100644 index 00000000..fbf49ab4 --- /dev/null +++ b/docs/source/quick_start/rt-thread/img/rtt_menuconfig2.png diff --git a/docs/source/quick_start/rt-thread/img/stm32cubemx.png b/docs/source/quick_start/rt-thread/img/stm32cubemx.png Binary files differnew file mode 100644 index 00000000..a6ca5078 --- /dev/null +++ b/docs/source/quick_start/rt-thread/img/stm32cubemx.png diff --git a/docs/source/quick_start/rt-thread/img/stm32cubemx2.png b/docs/source/quick_start/rt-thread/img/stm32cubemx2.png Binary files differnew file mode 100644 index 00000000..e29254bb --- /dev/null +++ b/docs/source/quick_start/rt-thread/img/stm32cubemx2.png diff --git a/docs/source/quick_start/rt-thread/img/stm32cubemx_clk.png b/docs/source/quick_start/rt-thread/img/stm32cubemx_clk.png Binary files differnew file mode 100644 index 00000000..41a7aae8 --- /dev/null +++ b/docs/source/quick_start/rt-thread/img/stm32cubemx_clk.png diff --git a/docs/source/quick_start/rt-thread/rt-thread.md b/docs/source/quick_start/rt-thread/rt-thread.md new file mode 100644 index 00000000..7c57a47c --- /dev/null +++ b/docs/source/quick_start/rt-thread/rt-thread.md @@ -0,0 +1,84 @@ +# RT-Thread based Software Package Development Guide + +[中文版](rt-thread_zh.md) + +To use CherryUSB package, you need to select it in the RT-Thread package manager. The specific path is as follows: + +``` +-> RT-Thread online packages + -> system packages + --- CherryUSB: tiny and portable USB stack for embedded system with USB IP + + CherryUSB Options ----> + USB Speed (FS) ---> + [*] Enable usb device mode + [*] Enable usb cdc acm device + [ ] Enable usb hid device + [ ] Enable usb dfu device + [ ] Enable usb msc device + [ ] Enable usb hub device + [ ] Enable usb audio device + [ ] Enable usb video device + + Version (latest) ---> +``` + +## Based ON STM32 Platform + +Please note that stm32 series have two usb ip. For usb ip, like stm32f0、stm32f1、stm32f3, for usb otg ip(as we know it is from **synopsys**),like stm32f4、stm32f7 and so on. + +### Use USB Device + +- Firstly,you should have a bsp project,and then go to `board\CubeMX_Config` directory, open file that suffix name with `.ioc` in **STM32CubeMX**. +- Enable **USB** or **USB_OTG_FS** or **USB_OTG_HS** in **Connectivity** List,enable USB IRQ in **NVIC Setting**. + + + +- Enable USB Clock for 48Mhz in **Clock configuration**. + + + +- Generate code. +- Copy **SystemClock_Config** into **board.c**. +- ~~Copy **MX_USB_OTG_FS_PCD_Init** or **MX_USB_OTG_HS_PCD_Init** into **main.c** if you use **usb_dc_hal.c**.Also, USB Irq from **it.c** needs the same.~~ +- Implement **usb_dc_low_level_init** and copy codes in from ``HAL_PCD_MspInit``. + +``` +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); + +} +``` + +- Implement **printf** or modify with **rt_kprintf** in **usb_utils.h**, usb stack needs. +- Now we can call some functions provided by **usb_stack**.Your should register descriptors、interfaces and endpoint callback firstly, and then call `usb_dc_init`. Example is as follows: + +``` +int main(void) +{ + extern void cdc_init(void); + cdc_init(); + usb_dc_init(); + while (1) + { + uint8_t data_buffer[10] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x31, 0x32, 0x33, 0x34, 0x35 }; + usbd_ep_write(0x81, data_buffer, 10, NULL); + rt_thread_mdelay(500); + } +} +``` + +- How to register class you can go to [stm32 class examples](https://github.com/sakumisu/usb_stack/tree/master/demo/stm32/stm32f103c8t6/example) for a reference. + +### CDC Demo Demonstration + + + +### Video manual + +If you have problem from steps above, you can see this video:[Use USB Stack in RT-Thread package manager](https://www.bilibili.com/video/BV1Ef4y1t73d?p=26)。
\ No newline at end of file diff --git a/docs/source/quick_start/rt-thread/rt-thread_zh.md b/docs/source/quick_start/rt-thread/rt-thread_zh.md new file mode 100644 index 00000000..561f657d --- /dev/null +++ b/docs/source/quick_start/rt-thread/rt-thread_zh.md @@ -0,0 +1,148 @@ +# 基于 RT-Thread 软件包开发指南 + +[English Version](rt-thread.md) + +使用 CherryUSB package 需要在 RT-Thread 的包管理器中选择它,具体路径如下: + +``` +-> RT-Thread online packages + -> system packages + --- CherryUSB: tiny and portable USB stack for embedded system with USB IP + + CherryUSB Options ----> + USB Speed (FS) ---> + [*] Enable usb device mode + [ ] Enable usb host mode + [*] Enable usb cdc acm device + [ ] Enable usb hid device + [ ] Enable usb dfu device + [ ] Enable usb msc device + [ ] Enable usb hub device + [ ] Enable usb audio device + [ ] Enable usb video device + + Version (latest) ---> +``` + +## 基于 STM32 平台 + +STM32 系列单片机有两种 USB IP,分别是 USB IP 和 USB OTG IP。其中 USB IP,例如 STM32F0、STM32F1、STM32F3等等,USB OTG IP(我们都知道用的是 **synopsys** 公司的)的有 STM32F4、STM32F7、STM32H7等等。当前如果你需要使用 USB Device 功能,porting 接口提供了两种,一种是适配 USB IP的 **fsdev**,另一种是适配 USB OTG IP 的 **synopsys**。 + +### 使用 USB Device 功能 + +- 首先,你需要有一个 bsp 工程,之后进入到 `board\CubeMX_Config` 目录下,使用 **STM32CubeMX** 打开后缀名为 `.ioc` 的文件。 +- 进入 **Connectivity** 选项,选择 **USB** 或者 **USB_OTG_FS** 或者 **USB_OTG_HS**,并使能 device 功能,在 **NVIC Setting** 中开启 USB 中断。 + + + +- 在 **Clock configuration** 栏配置 USB 时钟为 48Mhz. + + + +- 点击 **Generate code**。 +- 复制 **SystemClock_Config** 函数内容到 **board.c** 中。 +- 实现 ``usb_dc_low_level_init``,并将 ``HAL_PCD_MspInit`` 里面内容复制进来,例如: + +``` +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); + +} +``` + +- 由于协议栈默认使用 `printf` 和 `malloc` 和 `free`,所以需要开启 libc 支持或者自己实现。 + + +- 使用 **menuconfig** 配置 **CherryUSB** 软件包,使能 usb device 并勾选需要的 device class。 + + +- 现在我们可以调用 CherryUSB 中的函数来注册描述符、接口、端点中断,并调用 `usb_dc_init`,示例如下: + +``` +#include <rtthread.h> +#include <rtdevice.h> +#include <board.h> +#include <stdio.h> + +extern void usb_dc_init(void); +int main(void) +{ + extern void cdc_init(void); + cdc_init(); + usb_dc_init(); + while (1) + { + uint8_t data_buffer[10] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x31, 0x32, 0x33, 0x34, 0x35 }; + usbd_ep_write(0x81, data_buffer, 10, NULL); + rt_thread_mdelay(500); + } +} + +``` + +- 关于如何注册 class 类可以参考 [stm32 class examples](https://github.com/sakumisu/usb_stack/tree/master/demo/stm32/stm32f103c8t6/example)。 + +### 使用 USB Host 功能 + +- 首先,你需要有一个 bsp 工程,之后进入到 `board\CubeMX_Config` 目录下,使用 **STM32CubeMX** 打开后缀名为 `.ioc` 的文件。 +- 进入 **Connectivity** 选项,选择 **USB_OTG_FS** 或者 **USB_OTG_HS**,并使能 **host only** 功能,在 **NVIC Setting** 中开启 OTG GLOBAL 中断,其余两个端点中断不需要。 + + + +- 在 **Clock configuration** 栏配置 USB 时钟为 48Mhz. +- 点击 **Generate code**。 +- 复制 **SystemClock_Config** 函数内容到 **board.c** 中。 +- 修改 **usb_hc_synopsys.c** 中 HAL 库头文件包含,例如 `#include "stm32f4xx_hal.h"`。 +- 手动增加 **xxx_hal_hcd.c** 和 **xxx_ll_usb.c** 文件 +- 由于协议栈默认使用 `printf` 和 `malloc` 和 `free`,所以需要开启 libc 支持或者自己实现。 + + +- 使用 **menuconfig** 配置 **CherryUSB** 软件包,使能 usb host(默认加载所有支持的 class)。 + + +- `main.c` 中调用 `usbh_initialize` 初始化 host 协议栈。 + +``` +#include <rtthread.h> +#include <rtdevice.h> +#include <board.h> +#include "usbh_core.h" +/* defined the LED0 pin: PH10 */ +#define LED0_PIN GET_PIN(H, 10) + +int main(void) +{ + /* set LED0 pin mode to output */ + rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT); + usbh_initialize(); + while (1) + { + rt_pin_write(LED0_PIN, PIN_HIGH); + rt_thread_mdelay(500); + rt_pin_write(LED0_PIN, PIN_LOW); + rt_thread_mdelay(500); + } +} + + +``` + +### Demo 演示 + +- cdc acm device demo + + +- host demo + + + + + +### 视频教程 + +如果对上述步骤还有问题,可以参考 [协议栈在 RT-Thread 包管理器中的使用](https://www.bilibili.com/video/BV1Ef4y1t73d?p=26)。
\ No newline at end of file diff --git a/docs/source/quick_start/stm32f429.rst b/docs/source/quick_start/stm32f429.rst new file mode 100644 index 00000000..6ec8b352 --- /dev/null +++ b/docs/source/quick_start/stm32f429.rst @@ -0,0 +1,2 @@ +基于 STM32F429 开发指南 +========================= diff --git a/docs/source/usb/img/1.png b/docs/source/usb/img/1.png Binary files differnew file mode 100644 index 00000000..e85ddf7a --- /dev/null +++ b/docs/source/usb/img/1.png diff --git a/docs/source/usb/img/10.png b/docs/source/usb/img/10.png Binary files differnew file mode 100644 index 00000000..bb57645e --- /dev/null +++ b/docs/source/usb/img/10.png diff --git a/docs/source/usb/img/11.png b/docs/source/usb/img/11.png Binary files differnew file mode 100644 index 00000000..11056e33 --- /dev/null +++ b/docs/source/usb/img/11.png diff --git a/docs/source/usb/img/12.png b/docs/source/usb/img/12.png Binary files differnew file mode 100644 index 00000000..4149d81e --- /dev/null +++ b/docs/source/usb/img/12.png diff --git a/docs/source/usb/img/13.png b/docs/source/usb/img/13.png Binary files differnew file mode 100644 index 00000000..29a544b2 --- /dev/null +++ b/docs/source/usb/img/13.png diff --git a/docs/source/usb/img/14.png b/docs/source/usb/img/14.png Binary files differnew file mode 100644 index 00000000..8ca094a4 --- /dev/null +++ b/docs/source/usb/img/14.png diff --git a/docs/source/usb/img/15.png b/docs/source/usb/img/15.png Binary files differnew file mode 100644 index 00000000..eba7b89b --- /dev/null +++ b/docs/source/usb/img/15.png diff --git a/docs/source/usb/img/16.png b/docs/source/usb/img/16.png Binary files differnew file mode 100644 index 00000000..259336ca --- /dev/null +++ b/docs/source/usb/img/16.png diff --git a/docs/source/usb/img/17.png b/docs/source/usb/img/17.png Binary files differnew file mode 100644 index 00000000..c42de390 --- /dev/null +++ b/docs/source/usb/img/17.png diff --git a/docs/source/usb/img/18.png b/docs/source/usb/img/18.png Binary files differnew file mode 100644 index 00000000..f08b6354 --- /dev/null +++ b/docs/source/usb/img/18.png diff --git a/docs/source/usb/img/19.png b/docs/source/usb/img/19.png Binary files differnew file mode 100644 index 00000000..2e6eb9ce --- /dev/null +++ b/docs/source/usb/img/19.png diff --git a/docs/source/usb/img/2.png b/docs/source/usb/img/2.png Binary files differnew file mode 100644 index 00000000..5b4f5f20 --- /dev/null +++ b/docs/source/usb/img/2.png diff --git a/docs/source/usb/img/20.png b/docs/source/usb/img/20.png Binary files differnew file mode 100644 index 00000000..a44898a8 --- /dev/null +++ b/docs/source/usb/img/20.png diff --git a/docs/source/usb/img/21.png b/docs/source/usb/img/21.png Binary files differnew file mode 100644 index 00000000..7aa81e95 --- /dev/null +++ b/docs/source/usb/img/21.png diff --git a/docs/source/usb/img/22.png b/docs/source/usb/img/22.png Binary files differnew file mode 100644 index 00000000..370d39f9 --- /dev/null +++ b/docs/source/usb/img/22.png diff --git a/docs/source/usb/img/23.png b/docs/source/usb/img/23.png Binary files differnew file mode 100644 index 00000000..e08db16e --- /dev/null +++ b/docs/source/usb/img/23.png diff --git a/docs/source/usb/img/3.png b/docs/source/usb/img/3.png Binary files differnew file mode 100644 index 00000000..b8ef0823 --- /dev/null +++ b/docs/source/usb/img/3.png diff --git a/docs/source/usb/img/4.png b/docs/source/usb/img/4.png Binary files differnew file mode 100644 index 00000000..f80c5366 --- /dev/null +++ b/docs/source/usb/img/4.png diff --git a/docs/source/usb/img/5.png b/docs/source/usb/img/5.png Binary files differnew file mode 100644 index 00000000..ec6a4ba2 --- /dev/null +++ b/docs/source/usb/img/5.png diff --git a/docs/source/usb/img/6.png b/docs/source/usb/img/6.png Binary files differnew file mode 100644 index 00000000..2d280398 --- /dev/null +++ b/docs/source/usb/img/6.png diff --git a/docs/source/usb/img/7.png b/docs/source/usb/img/7.png Binary files differnew file mode 100644 index 00000000..e7562f11 --- /dev/null +++ b/docs/source/usb/img/7.png diff --git a/docs/source/usb/img/8.png b/docs/source/usb/img/8.png Binary files differnew file mode 100644 index 00000000..a4ac6ad4 --- /dev/null +++ b/docs/source/usb/img/8.png diff --git a/docs/source/usb/img/9.png b/docs/source/usb/img/9.png Binary files differnew file mode 100644 index 00000000..bb57645e --- /dev/null +++ b/docs/source/usb/img/9.png diff --git a/docs/source/usb/img/overview1.png b/docs/source/usb/img/overview1.png Binary files differnew file mode 100644 index 00000000..fbaf5a19 --- /dev/null +++ b/docs/source/usb/img/overview1.png diff --git a/docs/source/usb/img/overview2.png b/docs/source/usb/img/overview2.png Binary files differnew file mode 100644 index 00000000..c8b3b779 --- /dev/null +++ b/docs/source/usb/img/overview2.png diff --git a/docs/source/usb/usb_basic.rst b/docs/source/usb/usb_basic.rst new file mode 100644 index 00000000..052b4a3d --- /dev/null +++ b/docs/source/usb/usb_basic.rst @@ -0,0 +1,232 @@ +USB 基本概念 +=========================== + +本文主要对 USB 官方手册 `usb2.0.pdf <https://www.usb.org/document-library/usb-20-specification>`_ 中提供的第五章、第七章、第八章、第九章进行讲解。 + +简介 +--------- + +USB 是什么?干什么用的?有什么优点?这些大家可以百度,我就不提了。主要先说 USB 的接口和速度根据不同的 USB 版本的分类,如图所示: + +.. figure:: img/overview1.png + +其次是 USB 需要满足的电平标准,有了电平标准后,下面说的信号状态就可以进行分类了。USB2.0 和 USB3.0 支持的电压范围和最大电流如下: + +.. figure:: img/overview2.png + +USB 信号状态 +----------------- + +首先我们需要了解的是 USB 的电气特性中的 Signaling Level,也就是信号状态。USB 主要是靠 D+ 和 D- 来实现不同的信号状态,然后进行通信。官方手册 7.1.7 中列举出了低速、全速和高速时的信号状态对应的 D+ 和 D- 需要满足的要求。 + +.. figure:: img/1.png +.. figure:: img/2.png +.. figure:: img/3.png + +- **差分 0 和差分 1**: 这两个状态用于通过 USB 进行的通用数据通信。当 D+线为高电平、 D-线为低电平时,该状态为差分 1。当 D+线为低电平、 D-线为高电平时,该状态为差分 0。 +- **J 状态和 K 状态**: 除了差分信号外, USB 规范还定义了其他两个差分状态: J 状态和 K 状态。它们的定义由设备速度决定。在全速和高速设备上, J 状态为差分 1 而 K 状态是差分 0。在低速设备上,该情况则相反。 +- **单端 0( SE0)**: 在 D+和 D-均为低电平时所发生的状态。该状态表示一个复位、断连或数据包的结束。 +- **单端 1( SE1)**: 在 D+和 D-均为高电平时发生的状态。不会故意生成该状态,并且不能在 USB 设计中出现。 +- **闲置**: 必须在发送一个数据包的前后发生的状态。如果一个数据线为低电平,而另一个数据线为高电平,则表示闲置状态。高电平和低电平的定义由设备的速度决定。在全速设备上,闲置状态是指 D+为高电平、 D-为低电平。在低速设备上,该情况则相反。 +- **恢复**: 用于使设备从挂起状态唤醒。通过发送一个 K 状态实现该操作。 +- **数据包的开始( SOP)**: 当 D+和 D-线从闲置状态转换到 K 状态时,将在开始低速或全速数据包前发生。 +- **数据包的结束( EOP)**: 在低速或全速数据包结束时发生。当 SE0 状态持续两位时间(后面的内容将介绍位时间)以及 J 状态持续 1 位时间时,将发生 EOP。 +- **复位**: 在 SE0 状态持续 10 ms 时发生。在 SE0 至少持续 2.5 ms 后,该设备会复位,并开始进入复位状态。 +- **保持活动( Keep Alive)**: 在低速设备中使用的信号。低速设备缺少了一个帧起始数据包(用于防止挂起状态)。每次经过 1 ms,它们都会使用一个 EOP 来防止设备进入挂起状态。 + +.. note::这里需要注意的一点就是, J K状态和差分0/1,对于低速来说,和全速/高速是相反的。 + +下面我们通过一个波形,来区分这些信号状态: + +.. figure:: img/4.png + +- 第一个红框,可以看出是一个数据包的开始,并且假设这是一个全速设备,那么D+ 为高,D- 为低,是一个闲置状态。 +- 第二个红框,D+为低,D- 为高,说明是一个 K 状态,由 闲置转 K 状态说明他是一个 SOP。 +- 第三个红框开始表示数据,表示 JKJKJKJKJK。 +- 第四个红框表示 SE0 ,因为D+和 D-均为低电平。 +- 第五个红框,而 SE0 持续了一段时间后,变成了 D+高,D- 低,说明他是一个 J 状态,从 SE0 切换成 J 状态,说明他是一个 EOP。 + +USB 速度识别 +--------------------- + +USB 的速度是如何判定的? 这个见手册 7.1.5.1。USB 的速度检测主要是靠 D+ 和 D-线上拉 1.5K决定,如果 D+上拉1.5k,则该设备为全速设备,如果 D-上拉1.5k,则为低速设备。而高速设备初始是以一个全速设备的身份出现,和全速设备一样,D+线上有一个1.5k的上拉电阻。USB2.0的hub把它当作一个全速设备,之后,hub 和设备通过一系列握手信号确认双方的身份,最终判定该设备为高速设备。 + +.. figure:: img/5.png + +USB 连接与断开检测 +--------------------- + +那么 当我们的设备插上 USB 主机时,主机是如何知道有设备插入或者拔出呢?手册 7.1.7.3 给出了答案,如图所示: + +.. figure:: img/6.png +.. figure:: img/7.png + +首先是连接检测,主机检测到某一个数据线电平拉高保持了一段时间,就认为有设备连接上来了。低速设备连接时,主机会检测到D-线被拉高,全速/高速设备连接时,主机会检测到D+线被拉高。 +而断开检测,则是主机端D+、D-数据线上的下拉电阻起作用,断开后使得二者都在低电平;当低电平持续 TDDIS 时间就会被主机认为是断开状态。上图中,TDDIS在2到2.5us之间。 + +USB 电源 +--------------------- + +作为 USB 电源时, USB 设备可被划分为两种设备类型:总线供电和自供电。 + +- 总线供电是 USB 设计的一个优势。由于设备通过总线供电,因此不需要使用笨重的内部或外部电源,它仍能够维持自身操作。总线可由主机或集线器供电。使用某个总线供电的设备时,用户将设备配置为某种状态前必须考虑其功耗。 +- 自供电设备通过使用外部电源(如直流电源适配器或电池)为自己供电。自供电设备在进行设计的过程中需要考虑到一些注意事项。 USB 规范要求自供电设备一直监控自己的 VBUS 线。 VBUS 不存在的时间内,设备必须断开提供给 D+/D-线上的上拉电阻的电源,从而防止向主机或集线器供电。 否则,会导致 USB 合规性测试发生失败。但是自供电集线器能够从总线获得最多 100 mA 的电流。 + +USB 设备状态 +--------------------- + +在 USB 插上主机的那一刻, USB 设备本身的设备状态是会变化的。而这个设备状态,后面如果学习到枚举过程,可以知道,其实这段变化描述的就是枚举过程。这部分见手册 9.1.1。 + +.. figure:: img/9.png + +- 连接状态: 当将某个设备插入到主机/集线器,但主机/集线器不给 VBUS 线供电时,会出现这种状态。它通常在集线器检测到一个过流事件时出现。虽然仍连接着设备,但主机移除了供给它的电源。 +- 供电: 某个设备被连接到 USB 上并得到供电,但仍未接收到一个复位请求。 +- 默认: 某个设备被连接到 USB 上、得到供电,并且由主机进行了复位。这时,设备没有任何设备地址。 设备会响应地址 0。 +- 地址: 某个设备被连接到 USB、得到供电、被复位,并且有一个唯一的地址。但是设备仍未得到配置。 +- 配置: 设备已经连接到 USB、得到供电、被复位、具有唯一的地址、得到配置,但尚未进入挂起状态。此时,总线供电设备能够消耗超过 100 mA 的电流。 +- 挂起: 如上面所述,设备已经建立好了连接,并且得到配置,但在 3 ms 时间内不会进行任意总线操作。 + +翻译成中文图就是: + +.. figure:: img/10.png + +USB 编码与位填充 +--------------------- + +首先,USB 的数据是串行发送的,就像 UART、I2C、SPI 等等,连续的01 信号只通过一根数据线发送给接受者。但是因为发送者和接收者运行的频率不一样,信号的同步就是个问题,比如,接受者接收到了一个持续一段时间的低电平,无法得知这究竟是代表了 5 个 0 还是 1000 个 0。一个解决办法,就是在传输数据信号的同时,附加一个时钟信号,用来同步两端的传输,接受者在时钟信号的辅助下对数据信号采样,就可以正确解析出发送的数据了,比如 I2C 就是这样做的,SDA 来传输数据,SCL 来传输同步时钟: + +.. figure:: img/11.png + +虽然这样解决了问题,但是却需要附加一根时钟信号线来传输时钟。因为USB没有时钟信号,有没有不需要附加的时钟信号,也能保持两端的同步呢? +有的,这就是 RZ 编码(Return-to-zero Code),也叫做归零编码。 + +RZ 编码(Return-to-zero Code) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +RZ 编码(Return-to-zero Code),也叫做归零编码。在 RZ 编码中,正电平代表逻辑 1,负电平代表逻辑 0,并且,每传输完一位数据,信号返回到零电平,也就是说,信号线上会出现 3 种电平:正电平、负电平、零电平。 + +.. figure:: img/12.png + +从图上就可以看出来,因为每位传输之后都要归零,所以接受者只要在信号归零后采样即可,这样就不在需要单独的时钟信号。实际上, RZ 编码就是相当于把时钟信号用归零编码在了数据之内。这样的信号也叫做自同步(self-clocking)信号。 +这样虽然省了时钟数据线,但是还是有缺点的,因为在 RZ 编码中,大部分的数据带宽,都用来传输“归零”而浪费掉了。 + +NRZ 编码(Non-return-to-zero Code) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +去掉这个归零步骤,NRZ 编码(Non-return-to-zero Code)就出现了,和 RZ 的区别就是 NRZ 是不需要归零的。 + +.. figure:: img/13.png + +NRZI 编码(Non-Return-to-Zero Inverted Code) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +NRZI 编码(Non-Return-to-Zero Inverted Code)和 NRZ 的区别就是 NRZI 用信号的翻转代表一个逻辑,信号保持不变代表另外一个逻辑。这个见手册 7.1.8。 + +.. figure:: img/14.png + +如图所示,可以得出一个简单的记忆方式:遇到 0 的边沿电平就翻转,遇到 1 的边沿则不变。 + +位填充(bit-stuffing) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +但是,这样还是会有一个问题,就是虽然接受者可以主动和发送者的频率匹配,但是两者之间总会有误差。假如数据信号是 1000 个逻辑 1,经过 USB 的 NRZI 编码之后,就是很长一段没有变化的电平,在这种情况下,即使接受者的频率和发送者相差千分之一,就会造成把数据采样成 1001 个或者 999 个 1了。 +USB 对这个问题的解决办法,就是强制插 0,也就是(位填充)bit-stuffing,如果要传输的数据中有 6个连续的 1,发送前就会在第 6 个 1 后面强制插入一个 0,让发送的信号强制出现翻转,从而强制接受者进行频率调整。 +接受者只要删除 6 个连续 1 之后的 0,就可以恢复原始的数据了。这部分见手册 7.1.9。 + +.. figure:: img/15.png +.. figure:: img/16.png +.. figure:: img/17.png + +在数据被NRZI编码之前,在数据流中每六个连续的1之后插入一个0,以强制NRZI数据流中的过渡,这使接收器逻辑至少每七位有一次数据转换,以保证数据和时钟的锁定。比特填充是从同步模式开始启用。结束同步模式的数据 "一 "被算作是序列中的第一个 "一"。序列中的第一个。除了高速EOP期间,发射器的位填充总是被强制执行。如果需要按照 +位填充规则的要求,零位将被插入,即使它是数据包结束(EOP)信号前的最后一位。接收器必须对NRZI数据进行解码,识别填充位,并将其丢弃。 + +USB 字段(域) +--------------------- + +USB 字段构成了 USB 通信中最基本也是最小的单元,后面的包、事务,最根本都是由字段构成,而字段又是由比特构成。字段部分见手册 8.1。 + +.. note:: USB 的比特先行模式是按照 LSB 先行原则。 + +同步字段 +^^^^^^^^^^^^^^^^^^^^^^^^ + +在 USB 系统中,主机和设备不是共享一个时钟,这使得接收方没办法准确知道发送方什么时候发送数据,尽管能检测到SOP,但是远远不够,所有这个时候就需要同步字段,使得接收方和发送方收发过程中保持同步,所以任何一个包都要以同步字段开始。同步字段0x01,经过编码以后就是01010100B。 + +.. figure:: img/18.png + +包标识符字段 +^^^^^^^^^^^^^^^^^^^^^^^^ + +PID 由一个四位数据包类型字段和一个四位校验字段组成,占用 8 个bit,如图所示。 PID指示数据包的类型,并通过推断,数据包的格式和应用于数据包的错误检测类型包。 PID的四位校验字段是通过执行分组类型字段的一个补码来生成,从而确保PID的可靠解码,以便正确解释分组的其余部分,如果四个PID校验位不是它们各自的分组标识符位的补码,则存在PID错误。 + +.. figure:: img/19.png + +既然是 4个比特,说明了 PID 类型可以分为16种,从16种中,又细分成4类:令牌 PID,数据 PID,握手 PID 和特殊 PID。 + +.. figure:: img/20.png + +地址字段 +^^^^^^^^^^^^^^^^^^^^^^^^ + +地址字段又分为设备地址字段和端点地址字段,其中设备地址字段占用 7 个bit,除去0 地址,主机可以分配的地址有 127个。 + +.. figure:: img/21.png + +端点地址字段占用 4个 bit,总共可以提供 16 个端点。 + +.. figure:: img/22.png + +帧号字段 +^^^^^^^^^^^^^^^^^^^^^^^^ + +帧号字段占用 11 个bit,主机每发出一个帧,帧号都会加1,如图所示。而高速设备中,帧中又包含微帧,1帧=8微帧,微帧则是加0.1。关于帧和微帧的概念,后续补充。 + +.. figure:: img/23.png + +数据字段 +^^^^^^^^^^^^^^^^^^^^^^^^ + +CRC 字段 +^^^^^^^^^^^^^^^^^^^^^^^^ + +USB 包 +--------------------- + +令牌包 +^^^^^^^^^^^^^^^^^^^^^^^^ + +数据包 +^^^^^^^^^^^^^^^^^^^^^^^^ + +握手包 +^^^^^^^^^^^^^^^^^^^^^^^^ + +特殊数据包 +^^^^^^^^^^^^^^^^^^^^^^^^ + +USB 事务 +--------------------- + +SETUP 事务 +^^^^^^^^^^^^^^^^^^^^^^^^ + +IN 事务 +^^^^^^^^^^^^^^^^^^^^^^^^ + +OUT 事务 +^^^^^^^^^^^^^^^^^^^^^^^^ + +特殊事务 +^^^^^^^^^^^^^^^^^^^^^^^^ + +USB 传输 +--------------------- + +控制传输 +^^^^^^^^^^^^^^^^^^^^^^^^ + +批量传输 +^^^^^^^^^^^^^^^^^^^^^^^^ + +中断传输 +^^^^^^^^^^^^^^^^^^^^^^^^ + +同步传输 +^^^^^^^^^^^^^^^^^^^^^^^^
\ No newline at end of file diff --git a/docs/source/usb/usb_desc.rst b/docs/source/usb/usb_desc.rst new file mode 100644 index 00000000..25e4b08e --- /dev/null +++ b/docs/source/usb/usb_desc.rst @@ -0,0 +1,2 @@ +USB 描述符 +===========================
\ No newline at end of file diff --git a/docs/source/usb/usb_enum.rst b/docs/source/usb/usb_enum.rst new file mode 100644 index 00000000..e15d68c1 --- /dev/null +++ b/docs/source/usb/usb_enum.rst @@ -0,0 +1,2 @@ +USB 枚举 +===========================
\ No newline at end of file diff --git a/docs/source/usb/usb_request.rst b/docs/source/usb/usb_request.rst new file mode 100644 index 00000000..8ee9121a --- /dev/null +++ b/docs/source/usb/usb_request.rst @@ -0,0 +1,2 @@ +USB 设备请求 +===========================
\ No newline at end of file |
