一个嵌入式USB设备协议栈:Felis USB

FelisUSB是一个由作者为解决STM32HAL库和其他第三方USB协议栈存在的问题而开发的嵌入式USB设备协议栈。它支持多设备配置,模块化接口实现,且具有统一的配置管理和硬件抽象。用户可以通过简单的步骤集成到应用中,同时支持添加新的设备接口类。该项目已在GitHub上开源,采用MIT许可证。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        Felis USB是一个我刚开发的嵌入式USB设备协议栈。


season-studio/FelisUSB: A USB Stack for embedded system (github.com)icon-default.png?t=L892https://github.com/season-studio/FelisUSB

缘起

        说实话,这个项目是拖了挺长一段时间后,我才真正决定动手的。

        项目的缘起是因为我所在公司的一个技术预研项目。在公司的那个项目中,我需要指导一个新员工用STM32处理器实现一个USB摄像头(UVC)和HID组合设备。最初,我们用STM32 HAL库中自带的USB协议栈。但那个协议栈的实现稍微复杂了一点,造成较多的空间消耗。而且,STM32 HAL USB协议栈没有带多设备组合的实现框架。基于它去开发组合USB设备就相对要复杂一些。然后,我尝试了第三方的TeenyUSB和TinyUSB。不幸的是,TinyUSB不支持ISOC传输,也就不能用来开发UVC设备。而TeenyUSB却有一些BUG,会出现USB设备枚举慢、多次开关UVC设备后控制传输失败等一系列的问题。另外,这三款USB协议栈都有一个技术实现上的问题:它们没有很好的规划常数据和可变数据的存储,有一些常数据占用了RAM空间,无形中给应用的内存使用造成的一定压力。

        基于上述的因素,我本有意自己写一个USB协议栈。但是,我现在对纯粹的编码开发没有太大的兴趣,所以有段时间这个想法就一直只是想法。直到后来,公司那个技术预研项目的USB协议栈问题一直无法很好解决,我才在今年的中秋假期中动手把这个协议栈写出来。

主要特点

  • FelisUSB协议栈不需要软件系统支持,可以在裸机和带OS的工程中自由迁移;
    当然,由于避免对malloc等动态内存的依赖,协议栈里有些类型的实现会多增加一个指针的存储空间,也让检索过程增加一些指令操作周期,后续我有可能会实现一个依赖malloc的版本;
  • FelisUSB协议栈支持多个USB配置,支持多个USB设备接口类的分模块实现,确保设备接口层协议实现时的模块化和可伸缩性;
  • FelisUSB协议栈归一化USB相关配置,在USB设备描述符和USB配置描述符中已配置的信息,就不需要在代码中另行配置,确保了工程配置信息修改时能够一步到位,减少可能由于配置不同步造成的BUG;
  • FelisUSB协议栈进行了抽象,倡导从设备类接口层开始的代码不再关注端点号等硬件细节,只需要面向类对象、端点对象等抽象抽象体进行编程,让应用与硬件、逻辑与配置可以充分分离;

如何使用Felis USB构建应用

        使用Felis USB协议栈构建应用遵循以下步骤:

  • 新建应用工程,并添加必要的板级支持代码,例如:在STM32处理器环境下,用STM32Cube新建工程,并启用USB设备功能,使能USB中断,生成默认USB中断处理程序
  • 向工程中添加协议栈源码FelisUsbDevice.c
  • 向工程中添加设备类源码,例如:FelisUsbDClassHID.c
  • 向工程中添加目标板适配层源码,例如:stm32f4_hal_adapter.c
  • 新建目标板配置头文件FelisUsbBoard.h,并在其中添加对目标板适配层的引用,以及其他全局配置
  • 新建代码文件,定义设备描述符、配置描述符、字符串描述符等各类USB描述符数据
  • 在应用源码中引用协议栈头文件FelisUSB.h
  • 在应用源码中引用使用到的设备类头文件,例如:FelisUsbDClassHID.h
  • 在应用源码中声明设备类实例,并进行应用回调代码的编写
  • 在应用源码中声明协议栈设备实例,关联描述符和设备类示例
  • 在应用源码中调用启动协议栈的代码

以下是示例代码片段(完整示例代码可以sample目录下的内容):

///
/// FeliseUsbBoard.h 示例
#if	!defined(__FELIS_USB_BOARD_H__)
#define	__FELIS_USB_BOARD_H__

#include "adapters/stm32f4_hal_adapter.h"

#define FUSBD_ADPT_SPEED                (PCD_SPEED_FULL)

#define FUSB_DEBUG_OUT                  (3)

#endif	// __FELIS_USB_BOARD_H__

///
/// 应用代码示例
#include "FelisUSB.h"
#include "classes/FelisUsbDClassHID.h"
#include "desc.h"

extern fusbd_device_t gUsbDev;

uint8_t HidBuf[64];

static int OnHidReceived(fusbd_hid_pt pHid, void * pBuf)
{
	// TODO: ...
}

const fusbd_hid_t gHidClass = FUSBD_HID_CLASS(
	&gUsbDev,
	HidReportDescriptor, 
	FUSBD_HID_CLASS_RUNTIME(HidBuf),
	.OnReceived = OnHidReceived
);

fusbd_device_t gUsbDev = FUSBD_DEVICE(
	&FUSBD_DEVICE_CONFIG(
		&FUsbDeviceDescriptors,
		(fusbd_class_pt)&gHidClass
	)
);

...

int main()
{
	...
	fusbd_device_init(&gUsbDev);
	fusbd_device_start(&gUsbDev);
	fusbd_device_check_configed(&gUsbDev, FUSBD_TIMEOUT_INFINITY);
	// TODO: after the usb device is configed by the host
	...
}

如何基于Felis USB添加新的设备接口类

        基于Felis USB添加新的设备接口类主要包括以下三项工作:

  • 设计设备类的设计时数据 设备类的设计时数据指的是不随设备类运行状态变化而变化的数据,比如:设备类所需的额外的配置信息、设备类自定义的应用回调、设备类需要使用的额外缓冲区等等。 设备类的设计时数据需要继承基础设备类设计时数据。在结构体定义时,所有成员之前插入一句INHERIT_FUSBD_CLASS;即可实现继承关系。 将设备类的设计时数据与运行时数据分离,是为了有效节省对RAM的开销。
  • 设计设备类的运行时数据 设备类的运行时数据指的是在设备运行过程中发生变化的数据,比如:设备的运行状态、与主机交互的过程数据等等。 设备类的运行时数据需要继承基础设备类运行时数据。在结构体定义时,所有成员之前插入一句INHERIT_FUSBD_CLASS_RUNTIME; 即可实现继承关系。 合理规划运行时数据,有助于控制RAM的开销。
  • 实现设备类关注的各项回调函数 设备类的所有协议栈标准回调定义在fusbd_class_methods_t结构体中,设备类可根据自身的实际需求来实现其中的部分或所有回调函数。

代码示例: 请参考src/classes下的设备类实现文件。

获取FelisUSB

FelisUSB协议栈目前托管在GitHub上,以MIT许可开源。有兴趣的可以到以下git仓库中检出整个工程和示例。

season-studio/FelisUSB: A USB Stack for embedded system (github.com)icon-default.png?t=L892https://github.com/season-studio/FelisUSB

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值