- 基本概念
USB(Universal Serial Bus):通用串行总线。 USB HID(Universal Serial Bus-Human Interface Device) :是指人机交互设备,如 键盘、鼠标等 USB MSC(Mass Storage class):是指大容量存储设备,如 U盘等
1、通用串行总线全速接口(USBFS)
GD32 MCU 是通过USBFS实现的USB主机或设备功能。USBFS包含了一个内部的全速USB PHY,不再需要外部的PHY芯片。USBFS可以提供USB2.0协议所定义的所有4种传输方式(控制传输、批量传输、中断传输、同步传输)。 USBFS不仅提供了主机模式(Host)和设备模式,也提供了OTG模式:
- 主机模式:如U盘插到电脑上,电脑可以读写U盘里的内容,电脑端的USB接口就是主机模式。
- 设备模式:参考主机模式的描述,U盘就是设备模式。USB设备还有如鼠标、键盘。
- OTG模式:可以在主机模式和设备模式间切换。
1.1 硬件连接
1.1.1 信号线
I/O端口 | 类型 | 描述 |
---|
VBUS | 输入 | 总线电源端口 | DM | 输入/输出 | 差分信号D- 端口 | DP | 输入/输出 | 差分信号D+ 端口 | ID | 输入 | USB识别:微连接器识别端口 |
1.1.2 连接示意图
USBFS工作在主机模式下,VBUS是5v电源检测引脚(USB协议定义的)。内部PHY不能提供5v VBUS电源,仅在VBUS信号线上具有电压比较器和充放电电路。如果应用需要VBUS电源,则需要一个外部的供电电源IC。在主机模式下,USBFS与USB连接头之间可以不连接,因为USBFS并不检测VBUS引脚的电平状态并假定5v供电电源一直存在。
USBFS工作在设备模式下,USBFS_GCCFG寄存器中的VBUSIG控制位决定是否启用VBUS检测电路。如果设备不需要检测VBUS引脚电压,可以释放VBUS引脚作为其他用途。否则,VBUS引脚必须连接,并且USBFS需要不断的检测VBUS电平状态。一旦VBUS电压降至所需有效值以下,需要立即关闭DP信号线上的上拉电阻,这样会产生一个断开状态。
- OTG模式下连接示意图
当 USBFS 工作在 OTG 模式下时 USBFS需要以下四个引脚: DM、 DP、 VBUS 和 ID,并且需要使用电压比较器检测这些引脚的电压。USBFS 也包含 VBUS 充电和放电电路,用以完成 OTG 协议中所描述的 SRP 请求。 主机模式还是设备模式由ID 引脚的电平状态所决定。在实现 HNP 协议的过程中, USBFS 控制上拉和下拉电阻。
1.2 USBFS/USBHS性能
USBFS 接口模块可以作为仅支持全速(FS, 12Mbps)传输的的设备模式运行,也可以作为支持全速(FS, 12Mbps) 与低速(LS, 1.5Mbps)传输的主机模式运行。
USBHS 接口模块具有 USBFS 接口模块所有的特性及功能,并且在此基础之上, USBHS 接口模块可支持 USB2.0 高速(480Mbps)主机或设备。
1.3 USBFS模块固件库
1.3.1 USBFS固件库架构
以MSC 主机类介绍
1.3.2 主机状态机
USBFS的固件库驱动是通过状态机嵌套和状态机查表的方式进行处理的。 主机状态机包含: (1)主机状态机
- 主机状态机处理:usbh_core.c
- 主机状态轮询函数:
usbh_status_enum host_state_polling_fun (usb_core_handle_struct *pudev,
usbh_host_struct *puhost,
void *pustate)
state_table_struct host_handle_table[HOST_HANDLE_TABLE_SIZE] =
{
{HOST_IDLE, HOST_EVENT_ATTACHED, HOST_DEV_ATTACHED, only_state_move },
{HOST_DEV_ATTACHED, HOST_EVENT_ENUM, HOST_ENUMERATION, only_state_move },
{HOST_ENUMERATION, HOST_EVENT_USER_INPUT, HOST_USER_INPUT, only_state_move },
{HOST_USER_INPUT, HOST_EVENT_CLASS_REQ, HOST_CLASS_REQUEST, only_state_move },
{HOST_CLASS_REQUEST, HOST_EVENT_CLASS, HOST_CLASS, only_state_move },
{HOST_CLASS, HOST_EVENT_ERROR, HOST_ERROR, only_state_move },
{HOST_ERROR, HOST_EVENT_IDLE, HOST_IDLE, only_state_move },
{HOST_DEV_DETACHED, HOST_EVENT_IDLE, HOST_IDLE, only_state_move },
{HOST_CLASS_REQUEST, HOST_EVENT_ERROR, HOST_ERROR, only_state_move },
};
(2)枚举状态机 枚举的作用:主机识别到设备连接后,发起的一系列通信,由此主机获得设备的相关信息。
- 枚举状态机处理:usbh_std.c
- 枚举状态轮询函数:
usbh_status_enum enum_state_polling_fun (usb_core_handle_struct *pudev,
usbh_host_struct *puhost,
void *pustate)
state_table_struct enum_handle_table[ENUM_HANDLE_TABLE_SIZE] =
{
{ENUM_IDLE, ENUM_EVENT_SET_ADDR, ENUM_SET_ADDR, only_state_move },
{ENUM_SET_ADDR, ENUN_EVENT_GET_FULL_DEV_DESC, ENUM_GET_FULL_DEV_DESC, only_state_move },
{ENUM_GET_FULL_DEV_DESC, ENUN_EVENT_GET_CFG_DESC, ENUM_GET_CFG_DESC, only_state_move },
{ENUM_GET_CFG_DESC, ENUN_EVENT_GET_FULL_CFG_DESC, ENUM_GET_FULL_CFG_DESC, only_state_move },
{ENUM_GET_FULL_CFG_DESC, ENUN_EVENT_GET_MFC_STRING_DESC, ENUM_GET_MFC_STRING_DESC, only_state_move },
{ENUM_GET_MFC_STRING_DESC, ENUN_EVENT_GET_PRODUCT_STRING_DESC, ENUM_GET_PRODUCT_STRING_DESC, only_state_move },
{ENUM_GET_PRODUCT_STRING_DESC, ENUN_EVENT_GET_SERIALNUM_STRING_DESC, ENUM_GET_SERIALNUM_STRING_DESC, only_state_move },
{ENUM_GET_SERIALNUM_STRING_DESC, ENUN_EVENT_SET_CONFIGURATION, ENUM_SET_CONFIGURATION, only_state_move },
{ENUM_SET_CONFIGURATION, ENUN_EVENT_DEV_CONFIGURED, ENUM_DEV_CONFIGURED, only_state_move },
{ENUM_DEV_CONFIGURED, GO_TO_UP_STATE_EVENT, UP_STATE, goto_up_state_fun },
};
(3)控制传输状态机
- 控制传输状态机处理:usbh_ctrl.c
- 控制传输状态轮询函数:
usbh_status_enum ctrl_state_polling_fun (usb_core_handle_struct *pudev,
usbh_host_struct *puhost,
void *pustate)
state_table_struct ctrl_handle_table[CTRL_HANDLE_TABLE_SIZE] =
{
{CTRL_IDLE, CTRL_EVENT_SETUP, CTRL_SETUP, only_state_move },
{CTRL_SETUP, CTRL_EVENT_DATA, CTRL_DATA, only_state_move },
{CTRL_SETUP, CTRL_EVENT_STATUS, CTRL_STATUS, only_state_move },
{CTRL_SETUP, CTRL_EVENT_ERROR, CTRL_ERROR, only_state_move },
{CTRL_DATA, CTRL_EVENT_STATUS, CTRL_STATUS, only_state_move },
{CTRL_DATA, CTRL_EVENT_ERROR, CTRL_ERROR, only_state_move },
{CTRL_DATA, CTRL_EVENT_STALLED, CTRL_STALLED, only_state_move },
{CTRL_STATUS, CTRL_EVENT_COMPLETE, CTRL_COMPLETE, only_state_move },
{CTRL_STATUS, CTRL_EVENT_ERROR, CTRL_ERROR, only_state_move },
{CTRL_STATUS, CTRL_EVENT_STALLED, CTRL_STALLED, only_state_move },
{CTRL_ERROR, GO_TO_UP_STATE_EVENT, UP_STATE, goto_up_state_fun },
{CTRL_STALLED, GO_TO_UP_STATE_EVENT, UP_STATE, goto_up_state_fun },
{CTRL_COMPLETE, GO_TO_UP_STATE_EVENT, UP_STATE, goto_up_state_fun },
};
状态机流程示意: 状态机切换过程: 在HOST_DEV_ATTACHED状态下,如果接收到HOST_EVENT_ENUM事件,将进入HOST_ENUMERATION状态,在HOST_ENUMERATION状态下,将进入到枚举状态机中处理。在ENUM_DEV_CONFIGURED状态下,接收到 UP_STATE 事件,表明枚举完成, 将返回到上层主机状态机中继续处理。在枚举的过程中,需要控制传输,将会继续进入到控制传输状态机(更下一层状态机)中处理。在一次控制传输中,初始状态为 CTRL_IDLE,当一次控制传输完成状态将转移到CTRL_COMPLETE,然后将会返回上层状态机。
状态机的转移使用scd_table_push()函数将上层的状态机保存到状态机堆栈中,使用 scd_table_pop()函数返回至上层状态机中。
1.4 USBFS中断
在使用GD32 MCU开发USB MSC Host功能时,要开启USBFS的全局中断。此部分尚未搞清楚?
2、USB读写U盘记录
2.1 USB时钟
USBFS使用的USB时钟需要配置为48MHz。 从GD32 MCU时钟树可以看出 USB的48MHz时钟源有2个选择: 1)内部的 48MHz IRC 2)外部时钟hxtal 经过PLL 分频后得到 当时钟为200MHz时USB不稳定问题,需要修改时钟配置选择内部 RC48M 或 修改PLLAI的分频系数 可以参考这位大哥的博文GD32F450 200M时USB不稳定 https://www.cnblogs.com/zwj412/p/10026393.html
2.2 用户回调函数
从目前查看的USB相关资料看,在开发USB功能时,主要的工作是 1)移植USBFS固件库 2)添加用户回调处理函数(usbh_usr.c), 在USB不同状态时用户需要进行的处理。 主要涉及的回调函数有
usbh_user_callback_struct usr_cb =
{
usbh_user_init,
usbh_user_deinit,
usbh_user_device_connected,
usbh_user_device_reset,
usbh_user_device_disconnected,
usbh_user_over_current_detected,
usbh_user_device_speed_detected,
usbh_user_device_desc_available,
usbh_user_device_address_assigned,
usbh_user_configuration_descavailable,
usbh_user_manufacturer_string,
usbh_user_product_string,
usbh_user_serialnum_string,
usbh_user_enumeration_finish,
usbh_user_userinput,
usbh_usr_msc_application,
usbh_user_device_not_supported,
usbh_user_unrecovered_error
};
|