本帖最后由 vsf 于 2018-4-9 19:36 编辑
1. 数据结构
struct vsfusbd_iface_t
{
// public
struct vsfusbd_class_protocol_t *class_protocol;
void *protocol_param;
// private
......
};
struct vsfusbd_config_t
{
// public
vsf_err_t (*init)(struct vsfusbd_device_t *device);
vsf_err_t (*fini)(struct vsfusbd_device_t *device);
uint8_t num_of_ifaces;
struct vsfusbd_iface_t *iface;
// private
......
};
struct vsfusbd_device_t
{
// public
uint8_t num_of_configuration;
struct vsfusbd_config_t *config;
struct vsfusbd_desc_filter_t *desc_filter;
uint8_t device_class_iface;
struct vsfhal_usbd_t *drv;
int32_t int_priority;
void (*on_EVENT)(struct vsfusbd_device_t *device,
enum vsfusbd_usr_evt_t evt, void *param);
// private
......
};
VSF种的USB设备端协议栈,基本只需要按照需要,定义好数据结构,然后配合简单的代码就可以实现功能。
其中,最主要的就是定义vsfusbd_device_t结构,表明是实现什么USB设备,以及相应的设备参数。
struct vsfusbd_device_t:
1. uint8_t num_of_configuration:USB设备的配置数量,一般为1
2. struct vsfusbd_config_t *config:USB设备的配置数组指针
3. struct vsfusbd_desc_filter_t *desc_filter:设备的描述符列表
4. uint8_t device_class_iface:设备默认的设备类型对应的接口
5. struct vsfhal_usbd_t *drv和int32_t int_priority:底层USB驱动接口和中断优先级
6. void (*on_EVENT)(......):事件回调接口,一般设置为NULL
栗子:
.usbd.device.num_of_configuration = dimof(usrapp.usbd.config),
.usbd.device.config = usrapp.usbd.config,
.usbd.device.desc_filter = (struct vsfusbd_desc_filter_t *)usrapp_param.usbd.StdDesc,
.usbd.device.device_class_iface = 0,
.usbd.device.drv = (struct vsfhal_usbd_t *)&vsfhal_usbd,
.usbd.device.int_priority = 0xFF,
struct vsfusbd_config_t:
1. init和fini:配置初始化和终止化接口,一般设置为NULL
2. uint8_t num_of_ifaces:接口数量
3. struct vsfusbd_iface_t *iface:接口数组指针
栗子:
.usbd.config[0].num_of_ifaces = dimof(usrapp.usbd.ifaces),
.usbd.config[0].iface = usrapp.usbd.ifaces,
struct vsfusbd_iface_t:
1. struct vsfusbd_class_protocol_t *class_protocol:接口类驱动
2. void *protocol_param:接口类参数
栗子:
.usbd.ifaces[0].class_protocol = (struct vsfusbd_class_protocol_t *)&vsfusbd_CDCACMControl_class,
.usbd.ifaces[0].protocol_param = &usrapp.usbd.cdc.param,
.usbd.ifaces[1].class_protocol = (struct vsfusbd_class_protocol_t *)&vsfusbd_CDCACMData_class,
.usbd.ifaces[1].protocol_param = &usrapp.usbd.cdc.param,
对于USB CDC(USB转串口),需要实现2个接口,一个是CDCACM控制接口(vsfusbd_CDCACMControl_class),一个是CDCACM数据接口(vsfusbd_CDCACMData_class)。当然,还需要应用程序设置要usrapp.usbd.cdc.param的数据结构。
描述符列表栗子:
.usbd.StdDesc =
{
VSFUSBD_DESC_DEVICE(0, usrapp_param.usbd.DeviceDescriptor, sizeof(usrapp_param.usbd.DeviceDescriptor)),
VSFUSBD_DESC_CONFIG(0, 0, usrapp_param.usbd.ConfigDescriptor, sizeof(usrapp_param.usbd.ConfigDescriptor)),
VSFUSBD_DESC_STRING(0, 0, usrapp_param.usbd.StringLangID, sizeof(usrapp_param.usbd.StringLangID)),
VSFUSBD_DESC_STRING(0x0409, 1, usrapp_param.usbd.StringVendor, sizeof(usrapp_param.usbd.StringVendor)),
VSFUSBD_DESC_STRING(0x0409, 2, usrapp_param.usbd.StringProduct, sizeof(usrapp_param.usbd.StringProduct)),
VSFUSBD_DESC_STRING(0x0409, 4, usrapp_param.usbd.StringFunc_CDC, sizeof(usrapp_param.usbd.StringFunc_CDC)),
VSFUSBD_DESC_NULL,
},
定义了设备描述符,配置描述符,各种字符串描述符。具体的描述符就不说了,只是简单数组。
这些数据结构如果定义OK之后,要启动USB就非常简单了:
vsfusbd_device_init(&app->usbd.device);
vsfusbd_connect(&app->usbd.device);
最简单的启动代码只需要2行,2个API即可。当然,如果为了调试方便,可以在启动的时候,先断开USB的上拉电阻200ms,然后再启动USBD:
static void usrapp_usbd_conn(void *p)
{
struct usrapp_t *app = (struct usrapp_t *)p;
vsfusbd_device_init(&app->usbd.device);
vsfusbd_connect(&app->usbd.device);
if (app_hwcfg.usbd.pullup.port != VSFHAL_DUMMY_PORT)
vsfhal_gpio_set(app_hwcfg.usbd.pullup.port, 1 << app_hwcfg.usbd.pullup.pin);
}
void usrapp_srt_init(struct usrapp_t *app)
{
STREAM_INIT(&app->usbd.cdc.stream_rx);
STREAM_INIT(&app->usbd.cdc.stream_tx);
vsfshell_init(&app->shell);
if (app_hwcfg.usbd.pullup.port != VSFHAL_DUMMY_PORT)
{
vsfhal_gpio_init(app_hwcfg.usbd.pullup.port);
vsfhal_gpio_clear(app_hwcfg.usbd.pullup.port, 1 << app_hwcfg.usbd.pullup.pin);
vsfhal_gpio_config(app_hwcfg.usbd.pullup.port, app_hwcfg.usbd.pullup.pin, VSFHAL_GPIO_OUTPP);
}
vsfusbd_disconnect(&app->usbd.device);
vsftimer_create_cb(200, 1, usrapp_usbd_conn, app);
}
usrapp_srt_init为初始化软实时的代码,这里初始化了CDC的收发数据流,然后初始化USB上拉控制GPIO,并且关闭上拉,同时调用vsfusbd_disconnect断开USB连接,最后启动200ms定时器。200ms之后,就是之前看到的USBD启动代码,然后使能USB的1.5K上拉。
需要用到的API:
1. vsfusbd_device_init:初始化USB设备
2. vsfusbd_connect:连接USB设备
3. vsfusbd_disconnect:断开USB设备
4. vsfusbd_wakeup:远程唤醒USB主机
|