一个开源嵌入式USB设备协议栈:FelisUSB

概述

        Felis USB 是一个嵌入式USB协议栈。它不依赖于软件系统支持,可以轻量级迁移使用。 Felis USB is an USB stack for embedded system. See introduction in English here.

源码链接:season-studio/FelisUSB:null_C - GitCode开源社区

为什么开发Felis USB

在开发Felis USB之前,我所在的公司有个技术预研的项目,需要用STM32单片机开发一个UVC和HID设备杂合的USB设备样机。STM32 HAL库中所带的USB协议栈抽象层实现稍微繁琐了一些,造成较多的空间资源消耗,而且默认没有实现多接口设备类的框架。我尝试了TinyUSB协议栈以及TeenyUSB协议栈。然而,TinyUSB协议栈没有支持ISOC端点的分配;TeenyUSB似乎存在一些问题,造成USB设备枚举速度慢、UVC接口多次切换后控制端点通讯异常等BUG。并且,这些协议栈都存在没有合理规划常数据和可变数据存储空间的问题,有部分常数据占用RAM空间,一定程度上带来RAM空间的浪费。 所以,经过综合考虑,我在中秋假期中自行开发了这款USB设备协议栈的第一个版本。

特点

  • FelisUSB协议栈不需要软件系统支持,可以在裸机和带OS的工程中自由迁移
  • FelisUSB协议栈支持多个USB配置,支持多个USB接口设备类的分模块实现,确保设备类接口层协议实现时的模块化和可伸缩性
  • FelisUSB协议栈归一化USB相关配置,在USB设备描述符和USB配置描述符中已配置的信息,就不需要在代码中另行配置,确保了工程配置信息修改时能够一步到位,减少配置不同步可能造成的BUG
  • FelisUSB协议栈进行了抽象,倡导从设备类接口层开始的代码不再关注端点号等硬件细节,只需要面向类对象、端点对象等抽象抽象体进行编程,让应用与硬件、逻辑与配置可以充分分离

主要功能更新与计划

目前版本中:

  • Felis USB协议栈只支持USB 2.0的Device端协议;
  • 硬件适配层只提供了STM32F4的实现;
  • 设备类接口只提供了自定义HID、非压缩帧的UVC设备类的实现

后续计划:

  • 这个真说不好。我的所学比较杂,目前也不主做嵌入式产品研发了。而且,说实在的,以中国大多数企业的现状来看,我所处的岗位甚至可能都不应该动手去写这样的协议栈。所以,我做这个可以说是用爱发电。后续计划就真谈不上明确的时间表。暂时的想法是,可能会先补充一些设备协议类的实现以及WCID的实现吧。

如何使用

使用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下的设备类实现文件。

详情使用介绍

请参考 usage_cn.md

设计说明

请参考 design_cn.md

参考与借鉴

正如前文所说,我在开发Felis USB之前,已经看过STM32 HAL库中的USB协议栈实现,也尝试过TinyUSB和TeenyUSB。所以,我的实现中对这三者有所参考和借鉴。 主要内容如下:

  • 对于USB底层通讯逻辑的实现,参考了STM32 HAL库的代码,主要是其中HAL几个回调的处理,以及Setup Request的处理
  • 借鉴了TinyUSB中,对于配置描述符的解析处理,即遇到接口描述符时,由设备类接口回调进行匹配,并越过被设备类接口回调所处理过的描述符
  • 借鉴了TeenyUSB在Set Config过程中进行端点PMA/FiFo缓冲区配置的思路
  • 借鉴了TeenyUSB中HID对Setup Request的处理逻辑

移植教程后续补上,蟹蟹参阅!!! 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/811383.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI时代的新星:Devin AI 工程师的崛起

近日,人工智能领域掀起了一股新浪潮,一家成立不到两个月的初创公司Cognition推出了一款名为Devin的全球首位AI工程师。这款AI工程师引起了业界的高度关注,其独特的特点和能力使其成为软件开发领域的一颗耀眼之星。 Devin并非仅仅是一款编写代…

欧盟网络安全局:公共数据空间中的个人数据保护设计(下)

三、应用场景分析:健康—医药用途 2020年欧盟发布欧盟医药战略,旨在应对制药行业面临的各种机遇和挑战,以确保欧盟公民对于药品的可获得性、可负担性和可持续性。[4]报告将药品数据空间作为一种可能的手段,旨在支持数据使用者对于药品市场供应情况和药品功效的研究和分析。…

Java复习第十七天学习笔记(转发、重定向,GET,POST),附有道云笔记链接

【有道云笔记】十七 4.3 转发、重定向、Get、POST、乱码 https://note.youdao.com/s/GD5TRksQ 一、转发 转发:一般查询了数据之后,转发到一个jsp页面进行展示 req.setAttribute("list", list); req.getRequestDispatcher("student_lis…

大厂面试:获取字符串的全排列

一、概念 现有一个字符串,要打印出该字符串中字符的全排列。例如输入字符串abc,则打印出由字符a、b、c所能排列出来的所有字符串abc、acb、bac、bca、cab和cba。 可以基于回溯法来解决这个问题。 二、代码 public class Permutation {//输出字符串str的全…

算法 第38天 动态规划1

509 斐波那契数 斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是: F(0) 0,F(1) 1 F(n) F(n - 1) F(n - 2),其中 n…

权限修饰符,代码块,抽象类,接口.Java

1&#xff0c;权限修饰符 权限修饰符&#xff1a;用来控制一个成员能够被访问的范围可以修饰成员变量&#xff0c;方法&#xff0c;构造方法&#xff0c;内部类 &#x1f47b;&#x1f457;&#x1f451;权限修饰符的分类 &#x1f9e3;四种作用范围由小到大(private<空着…

SV-704XT 100W网络有源音柱 校园广播音柱

SV-704XT 100W网络有源音柱 一、描述 SV-704XT是深圳锐科达电子有限公司的一款壁挂式网络有源音柱&#xff0c;具有10/100M以太网接口&#xff0c;可将网络音源通过自带的功放和喇叭输出播放&#xff0c;其采用防水设计&#xff0c;功率100W。SV-704XT作为网络广播播放系统的终…

【算法】斐波那契数列第n位 - 去重递归/双指针迭代

题目 给定n&#xff0c;求斐波那契数列第n位的数值。 斐波那契数列&#xff1a;0 1 1 2 3 5 8 13 …… 每个数等于前面两个数相加&#xff0c;第n位等于第(n - 1)位加上第(n - 2)位。 原理 去重递归 使用递归的方式计算出结果&#xff0c;但使用一个数组保存已经计算出来的值…

java 将 json 数据转为 java 中的对象

一、准备 json 数据 {"name": "mike","age": 17,"gender": 1,"subject": ["math","english"] }二、对应的java对象 package com.demo.controller;import lombok.Data; import java.util.List;Data pu…

什么是感知器 怎么学习感知器

什么是感知器&#xff1f; 感知器是一种简单的人工神经网络算法&#xff0c;也是最早的神经网络单元之一&#xff0c;由Frank Rosenblatt于1957年提出。它被设计用来进行二元分类&#xff0c;即判断输入数据属于哪一类&#xff08;例如&#xff0c;是或否&#xff09;。感知器…

蓝桥杯练习题 —— 01字串(python)

for i in range(32):number ((7 - len(str(bin(i)))) * "0") str(bin(i))[2:]print(number) 所用方法 以下代码用于实现十进制转二进制、八进制、十六进制&#xff1a; for i in range(100, 1000):a i // 100 # 百位b i % 100 // 10 # 十位c i % 10 …

回溯算法先导

撤销当前的操作 使用原因及解决的问题 基本上暴力搜索的问题 适用于 组合问题 [1,2,3,4] 两位数的组合有哪些切割问题 给定字符串,求切割方式使其字串都是回文子串子集问题 求 [1,2,3,4] 的子集排列组合 组合(不强调顺序)棋盘问题 如何理解回溯法 抽象为一个树形结构 回溯…

华为OD-C卷-最长子字符串的长度(一)[100分]

题目描述 给你一个字符串 s,首尾相连成一个环形,请你在环中找出 o 字符出现了偶数次最长子字符串的长度。 输入描述 输入是一个小写字母组成的字符串 输出描述 输出是一个整数 备注 1 ≤ s.length ≤ 500000s 只包含小写英文字母用例1 输入 alolobo输出 6说明 最长子字…

Python模块pyttsx3添加语音包

查询现有语音包信息:脚本import pyttsx3engine = pyttsx3.init() voices = engine.getProperty(voices) for voice in voices:print("Voice:")print(" - ID: %s" % voice.id)print(" - Name: %s" % voice.name)print(" - Languages: %s&qu…

MySQL 04-EMOJI 表情与 UTF8MB4 的故事

拓展阅读 MySQL View MySQL truncate table 与 delete 清空表的区别和坑 MySQL Ruler mysql 日常开发规范 MySQL datetime timestamp 以及如何自动更新&#xff0c;如何实现范围查询 MySQL 06 mysql 如何实现类似 oracle 的 merge into MySQL 05 MySQL入门教程&#xff0…

MySQL基础练习题:习题21-25

这部分主要是为了帮助大家回忆回忆MySQL的基本语法&#xff0c;数据库来自于MySQL的官方简化版&#xff0c;题目也是网上非常流行的35题。这些基础习题基本可以涵盖面试中需要现场写SQL的问题。 列出在部门sales工作的员工的姓名&#xff0c;假定不知道销售部的部门编号 sele…

产品思维训练 | 熊孩子任性打赏从产品角度有哪些方法可以规避?

本周话题&#xff1a; 抖音回应10岁儿童打赏主播10万&#xff1a;已全额退款。正值特殊时期&#xff0c;小朋友们花费在直播APP中的时间也不少。 对于打赏等行为&#xff0c;当然需要家长加强监督&#xff0c;除此之外&#xff0c;产品方面可以做什么措施&#xff0c;压制住胡…

【JS】获取接口返回 EventStream 结构的数据(即接收读取 stream 流)

文章目录 EventStream 是一种服务器推送的数据格式&#xff0c;可以用于实时数据传输。 接口返回的示例图 获取示例&#xff1a; // 这里的 url 为虚拟的&#xff0c;仅供演示用 fetch(https://test.cn.com/api/agent/2, {method: POST,headers: {Content-Type: applicatio…

Docker部署前后端项目

使用Docker部署前后端项目的全面指南 在现代软件开发中&#xff0c;Docker已经成为了部署应用程序的一种流行方式。它提供了一种轻量级的、可移植的、自给自足的解决方案&#xff0c;可以在不同的环境中一致地运行应用程序。本文将详细介绍如何使用Docker来部署一个包含前端和…

Hudi原理学习

Hudi原理学习 一、Hudi是什么 Hudi&#xff08;Hadoop Upsert Delete and Incremental&#xff09;是什么&#xff1a;围绕数据库内核构建的流式数据湖平台&#xff08;Streaming Data Lake Platform&#xff09; 简而言之&#xff0c;它是一个对计算和存储进行解耦的数据湖方…