VSF中实现了一个相对通用的USB设备端协议栈,可以通过移植芯片的USB SIE驱动,来支持不同的MCU。USB设备端协议栈的实现只用到了最基本的事件驱动机制,并且,USB的各个中断响应,没有实时性要求。VSF的USB代码都位于vsf/component/usb目录下,core目录下的vsfusbd.c是协议栈主体、dcd(device controller driver设备控制器驱动)目录下是USB设备控制芯片的驱动、class/device目录下是USB设备类的驱动。
先从应用角度来看,使用USB设备端协议栈只需要定义一个vsfusbd_device_t数据结构,然后调用vsfusbd_device_init即可,以下是典型的USBD应用代码:
static void usrapp_usbd_conn(void *p)
{
struct usrapp_t *app = (struct usrapp_t *)p;
vsfusbd_device_init(&app->usbd.device);
app->usbd.device.drv->connect();
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)
{
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);
}
app->usbd.device.drv->disconnect();
vsftimer_create_cb(200, 1, usrapp_usbd_conn, app);
}
应用层定义好app->usbd.device数据结构后,代码上就非常简单和固化了,在软实时初始化里,断开USB上拉,建立一个200ms的定时器,超时后执行usrapp_usbd_conn,调用vsfusbd_device_init、连接USB并且使能上拉。所以应用部分的关键就是在这个vsfusbd_device_t数据结构的定义,这个决定了USB实现的功能。
这里,以mscboot的应用代码作为示例,截取USB设备端数据结构的定义:
.usbd.msc.param.ep_in = 1,
.usbd.msc.param.ep_out = 1,
.usbd.msc.param.scsi_dev = &usrapp.mal.scsi_dev,
.usbd.ifaces[0].class_protocol = (struct vsfusbd_class_protocol_t *)&vsfusbd_MSCBOT_class,
.usbd.ifaces[0].protocol_param = &usrapp.usbd.msc.param,
.usbd.config[0].num_of_ifaces = dimof(usrapp.usbd.ifaces),
.usbd.config[0].iface = usrapp.usbd.ifaces,
.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,
device.drv指向一个vsfhal_usbd_t结构的数据,指定底层的USB设备驱动。常用的底层设备驱动有vsfhal_usbd(芯片内置的USB设备接口驱动)、vsfsdcd_usbd(GPIO模拟低速USB的接口驱动)、vbususbd_drv(虚拟vbus总线上实现的USB设备接口驱动)等等。device.int_priority定义驱动使用到的中断的优先级。这些的定义是和硬件有关的。
其他定义都和硬件无关,只是指定了实现什么样的USB设备。了解USB的人应该都知道,USB是由configuration、interface、endpoint组成的。一个设备可以有多个configuration,由device.num_of_configuration和device.config指定。上述代码里,只有一个configuration:
.usbd.config[0].num_of_ifaces = dimof(usrapp.usbd.ifaces),
.usbd.config[0].iface = usrapp.usbd.ifaces,
然后,每个configuration可以包含多个interface,上述代码里,也只有一个interface:
.usbd.ifaces[0].class_protocol = (struct vsfusbd_class_protocol_t *)&vsfusbd_MSCBOT_class,
.usbd.ifaces[0].protocol_param = &usrapp.usbd.msc.param,
这里的interface是vsfusbd_MSCBOT_class类的,也就是U盘的设备类。这里class_protocol指定了类协议,protocol_param指定了参数:
.usbd.msc.param.ep_in = 1,
.usbd.msc.param.ep_out = 1,
.usbd.msc.param.scsi_dev = &usrapp.mal.scsi_dev,
这个就是MSC类需要设置的参数。指定了输入输出的ep端口号,并且指定了一个scsi设备。
所以,总的来说,vsfusbd_device_t里定义了和硬件相关的设置、定义了描述符的设置、定义了从configuration到interface的结构、然后再定义各个interface的参数。有了这些信息,USB设备端协议栈就可以运行起来了。