手机网站 html,发簪做的比较好的网站,WordPress主题开源,房产网贷平台USB是很常用的接口#xff0c;目前大多数的设备都是USB接口的#xff0c;比如鼠标、键盘、USB摄像 头等#xff0c;在实际开发中也常常遇到USB接口的设备#xff0c;本章就来学习一下如何使能Linux内核自带的USB驱动。这里不会具体学习USB的驱动开发。
USB接口简介
什么是…USB是很常用的接口目前大多数的设备都是USB接口的比如鼠标、键盘、USB摄像 头等在实际开发中也常常遇到USB接口的设备本章就来学习一下如何使能Linux内核自带的USB驱动。这里不会具体学习USB的驱动开发。
USB接口简介
什么是USB
USB全称为Universal Serial Bus翻译过来就是通用串行总线。由英特尔与众多电脑公司提出来用于规范电脑与外部设备的连接与通讯。目前USB接口已经得到了大范围的应用已经是电脑、手机等终端设备的必配接口甚至取代了大量的其他接口。比如最新的智能手机均采用USB TypeC取到了传统的3.5mm耳机接口苹果最新的MacBook只有 USB TypeC接口至于其他的HDMI、网口等均可以通过USB TypeC扩展坞来扩展。
按照大版本划分USB目前可以划分为USB1.0、USB2.0、USB3.0以及正在即将到来的USB4.0。
USB1.0USB规范于1995年第一次发布由Inter、IBM、Microsoft等公司组成的USB-IF(USB Implement Forum)组织提出。USB-IF在1996年正式发布USB1.0理论速度为1.5Mbps。1998 年USBIF在USB1.0的基础上提出了USB1.1规范。USB2.0USB2.0依旧由Inter、IBM、Microsoft等公司提出并发布USB2.0分为两个版本:Full-Speed和High-Speed也就是全速(FS)和高速(HS)。USB2.0 FS的速度为12MbpsUSB2.0 HS速度为480Mbps。目前大多数单片机以及低端Cortex-A芯片配置的都是USB2.0接口比如STM32MP157。USB2.0全面兼容USB1.0标准。USB3.0USB3.0同样由Inter等公司发起的USB3.0最大理论传输速度为5.0GbpsUSB3.0引入了全双工数据传输USB2.0的480Mbps为半双工。USB3.0中两根线用于发送数据另外两根用于接收数据。在USB3.0的基础上又提出了USB3.1、USB3.2等规范USB3.1理论传输速度提升到了10GbpsUSB3.2理论传输速度为20Gbps。为了规范 USB3.0标准的命名USB-IF公布了最新的USB命名规范原来的USB3.0和USB3.1命名将不会采用所有的3.0 版本的USB都命名为 USB3.2以前的USB3.0、USB3.1和USB3.2分别叫做USB3.2 Gen1、USB3.2 Gen2、USB3.2 Gen 2X2。USB4.0目前还在标准定制中目前还没有设备搭载据说是在Inter的雷电3接口上改进而来。USB4.0的速度将提升到了40Gbps最高支持100W的供电能力只需要一根线就可以完成数据传输与供电极大的简化了设备之间的链接线数期待USB4.0设备上市。
如果按照接口类型划分的话USB就要分为很多种了最常见的就是USB A插头和插座如下图所示 使用过JLINK调试器的朋友应该还见过USB B插头和插座USB B插头和插座如下图所示 USB插头在不断的缩小由此产生了Mini USB接口Mini USB插头和插座如下图所示 比Mini USB更小的就是Micro USB接口了以前的智能手机基本都是Micro USB接口的Micro USB插头和插座如下图所示 现在最流行的就是USB Typec了正点原子的STM32MP1开发板使用的是USB Typec接口USB Typec插头和插座如下图所示 USB电气特性
Mini USB电气属性
先以Mini USB为例讲解一下USB的基本电气属性。Mini USB线一般都是一头为USB A插头一头为Mini USB插头。一共有四个触点也就是4根线这四根线的顺序如下图所示 如上图所示USB A插头从左到右线序依次为 1,2,3,4第1根线为VBUS电压为5V第2根线为D-第3根线为D第4根线为GND。USB采用差分信号来传输数据因此有D-和D两根差分信号线。仔细观察的话会发现USB A插头的1和4这两个触点比较 长2和3这两个触点比较短。1和4分别为VBUS和GND也就是供电引脚当插入 USB的时候会先供电然后再接通数据线。拔出的时候先断开数据线然后再断开电源线。
再观察一下Mini USB插头会发现Mini USB插头有5个触点也就是5根线线序 从左往右依次是1-5。第1根线为VCC(5V)第2根线为D-第3根线为D第4根线为ID第5根线为GND。可以看出Mini USB插头相比USB A插头多了一个ID线这个ID线用于 实现OTG功能通过ID线来判断当前连接的是主设备(HOST)还是从设备(SLAVE)。
USB是一种支持热插拔的总线接口使用差分线(D-和 D)来传输数据USB支持两种供电模式总线供电和自供电总线供电就是由USB接口为外部设备供电在USB2.0下总线供电最大可以提供500mA的电流。
USB拓补结构
USB是主从结构的也就是分为主机和从机两部分一般主机叫做Host从机叫做Device。主机通过USB A插座来连接外部的设备比如电脑作为主机对外提供USB A插座可以通过USB线来连接一些USB设备比如声卡、手机等。因此电脑带的USB A插座数量就决定了能外接多少个USB设备如果不够用的话可以购买USB集线器来扩展电脑的USB插口USB集线器也叫做USB HUBUSB HUB如下图所示 上图是一个一拖四的USB HUB也就是将一个USB接口扩展为4个。主机一般会带几个原生的USB主控制器比如STM32MP1就有两个原生的USB主控制器因此STM32MP1 对外提供两个USB接口这两个接口肯定不够用正点原子的STM32MP1开发板上有6个HOST接口六路都是USB2通过USB HUB芯片扩展出来的稍后会讲解其原理图。
虽然可以对原生的USB口数量进行扩展但是不能对原生USB口的带宽进行扩展比如STM32MP1的两个原生USB口都是USB2.0的带宽最大为480Mbps因此接到下面的所有USB设备总带宽最大为480Mbps。
USB只能主机与设备之间进行数据通信USB 主机与主机、设备与设备之间是不能通信的。因此两个正常通信的USB接口之间必定有一个主机一个设备。为此使用了不同的插头和插座来区分主机与设备比如主机提供 USB A插座从机提供Mini USB、Micro USB 等插座。在一个USB系统中仅有一个USB主机但是可以有多个USB设备包括USB功能设备和USB HUB最多支持127个设备。一个USB主控制器支持128个地址地址0是默认地址只有在设备枚举的时候才会使用地址0不会分配给任何一个设备。所以一个USB主控制器最多可以分配127个地址。整个USB的拓扑结构就是一个分层的金字塔形如下图所示 上图中可以看出从Root Hub开始一共有7层金字塔顶部是Root Hub这个是USB控制器内部的。图中的Hub就是连接的USB集线器Func就是具体的USB设备。
USB主机和从机之间的通信通过管道(Pipe)来完成管道是一个逻辑概念任何一个USB设备一旦上电就会存在一个管道也就是默认管道USB主机通过管道来获取从机的描述符、配置等信息。在主机端管道其实就是一组缓冲区用来存放主机数据在设备端管道对应一个特定的端点。
USB OTG
USB分为HOST(主机)和从机(或DEVICE)有些设备可能有时候需要做HOST有时候又需要做DEVICE配两个USB口当然可以实现但是太浪费资源了。如果一个USB接口既可以做HOST又可以做DEVICE那就太好了使用起来就方便很多。为此USB OTG 应运而生OTG是On-The-Go的缩写支持USB OTG功能的USB接口既可以做HOST也可以做DEVICE。为了区分当前的工作状态这里就引入了ID线这个概念前面讲解USB电气属性的时候已经说过了Mini USB插头有5根线其中一条就是ID线。ID线的高低电平表示USB口工作在HOST还是DEVICE模式
ID1OTG设备工作在从机模式。ID0OTG设备工作在主机模式。
支持OTG模式的USB接口一般都是Mini USB、Micro USB 等这些带有ID线的接口。正点原子的STM32MP1开发板OTG模式是使用USB Type C做接口没有ID线。USB Type C有自己的识别方法稍后会讲解TypeC接口电气属性。正点原子的STM32MP157开发板USB_OTG连接到了STM32MP1的USB1接口上。如果要使用OTG的主机模式那么就需要一根OTG线TypeC接口的OTG线如下图所示 可以看出TypeC OTG线一头是USB A插座一头是Typec插头将TypeC插头插入机器的TypeC口上需要连接的USB设备插到另一端的USB A插座上比如U盘。TypeC的CC引脚检查到USB设备已经接入就会建立USB设备为主模式机器就知道自己要做为一个主机用来连接外部的从机设备(U 盘)。
STM32MP1 USB接口简介
STM32MP157提供了两个USB2.0接口这两个USB接口都是支持高速模式也就是480Mbit/S这两个USB接口都内置了高速PHY。其中USB2支持OTG功能正点原子STM32MP157开发板上的USB OTG接口就是链接到USB2接口上的。USB1接口连接了一个HUB芯片实现了USB Host接口扩展。
STM32MP1内部集成了三个跟USB相关的控制器名字分别为USB OTG控制器、USB Host控制器和USB HS PHY控制器提供一个简称方便书写OTG、USBH和PHY。接着分析一下这三个控制器是如何工作的。
PHY控制器
PHY(英语Port Physical Layer)中文可称之为端口物理层是一个对OSI模型物理层的共同简称。PHY控制器主要是提供两个端口端口1已经规定分配给USB Host控制器端口2可以分配给USB OTG和USB Host。
OTG控制器
此控制器是支持OTG功能它的内部特性如下所示
此控制器有一个独立的内核USB OTG HS。该控制器支持HS、FS和LS模式不管是主机还是从机模式都支持HS/FS/LS硬件支持OTG信号、会话请求协议和主机协商协议支持8个双向端点还支持PHY接口。内嵌一个DMA。支持片上全速PHY、连接外部全速PHY的I2C接口和连接外部高速PHY的ULPL接口。具有采用高级FIFO控制的4 KB专用RAM。
OTG控制器有两个模式正常模式(normal mode)和低功耗模式(low power mode)。OTG控制器都可以运行在高速模式(HS 480Mbps)、全速模式(LS 12Mbps)和低速模式(1.5Mbps)。正常模式下每个OTG控制器都可以工作在主机(HOST)或从机(DEVICE)模式下每个USB控制器都有其对应的接口。低功耗模式顾名思义就是为了节省功耗USB2.0 协议中要求设备在上行端口检测到空闲状态以后就可以进入挂起状态。在从机(DEVICE)模式下端口停止活动3ms以后OTG控制器内核进入挂起状态。在主机(HOST)模式下OTG控制器内核不会自动进入挂起状态但是可以通过软件设置。不管是本地还是远端的USB主从机都可以通过产生唤醒序列来重新开始USB通信。
USBH控制器
USBH控制器这是一个主机控制器此控制器由EHCI控制器和OHCI控制器组成。USBH控制器只能做主机模式。
这里简单提一下OHCI、UHCI、EHCI和xHCI这四个是用来描述USB控制器规格 的区别如下
OHCI全称为Open Host Controller Interface这是一种USB控制器标准厂商在设计USB控制器的时候需要遵循此标准用于USB1.1标准。OHCI不仅仅用于USB也支持一些其他的接口比如苹果的Firewire等OHCI由于硬件比较难所以软件要求就降低了软件相对来说比较简单。OHCI主要用于非X86的USB比如扩展卡、嵌入式USB控制器。UHCI全称是Universal Host Controller InterfaceUHCI是Inter主导的一个用于USB1.0/1.1的标准与OHCI不兼容。与OHCI相比UHCI硬件要求低但是软件要求相应就高了因此硬件成本上就比较低。EHCI全称是Enhanced Host Controller Interface是Inter主导的一个用于USB2.0的USB控制器标准。EHCI仅提供USB2.0的高速功能至于全速和低速功能就由OHCI或UHCI来提供。xHCI全称是eXtensible Host Controller Interface是目前最流行的USB3.0控制器标准在速度、能效和虚拟化等方面比前三个都有较大的提高。xHCI支持所有速度种类的USB设备xHCI出现的目的就是为了替换前面三个。
通俗来讲OHCI就是FS模式也就是低速模式EHCI是HS模式也就是高速模式。
USB Typec电气属性
USB TypeC接口引脚定义
STM32MP157有两个USB2接口所以可以直接使用Mini USB或者Micro USB。但是目前USB TypeC接口非常普及为了方便使用正点原子STM32MP157开发板上的USB接口采用了TypeC。
接下来就看一下USB TypeC接口(根据USB协议也叫做USB3.1接口)电气属性由于TypeC功能比较复杂比如支持PD充电、显示、音频等这里只讲解一下TypeC的数据 通信部分。首先来看一下TypeC的接口定义这里只看母头的引脚定义如下图所示 从上图中可以看出标准的USB TypeC有24根线分为上下两部分明显比前面讲的Mini USB要多不少引脚这些引脚按照功能分类
A1、A12、B1、B12这4个引脚为GND。A2、A3、B2、B3这4个引脚是USB3.1特有的为超高速差分发送信号线这个是USB2.0和USB1.0所没有的。A10、A11、B10、B11这4个引脚也是USB3.1特有的为超高速差分接收信号线这个也是USB2.0和USB1.0所没有的。A4、A9、B4、B9VBUS引脚这个USB2.0也有。A5、B5CC1和CC2这2个引脚为USB3.1特有的配置通道引脚。Type-C的插座中有两个CC脚USB通信中的角色检测都是通过CC脚进行的。对于TypeC插头或者线缆正常只有一个CC引脚两个端口连接在一起之后只存在一个CC引脚连接通过检测哪一个CC有连接就可以判断连接的方向。如果USB线缆中有需供电的器件其中一个CC引脚将作为VCONN供电。 对于正点原子linux驱动教程里的USB章节来说主要使用CC1和CC2引脚来实现USB OTG功能。A8、B8SBU1和SBU2引脚这两个并不是USB信号而是用作其他功能的比如TypeC作为DP接口使用的时候SBU用作音频传输通道。A6、A7、B6、B7这4个引脚就是USB2.0的D和D-因为USB3.1要兼容USB2.0和USB1.0接口所以必须要有D和D-。
仔细看上图可看出上下两排引脚是对应的比如(A1,B1)、(A2,B2)等一直到(A12,B12)。这是因为USB3.1要有能够正反插因此上下两排引脚肯定要是一样的这样才能在正反插的时候都能正常工作。
上图是TypeC接口标准的24P母头引脚在进行TypeC母头选型的时候会发现也有16P甚至6P封装的接口。比如正点原子STM32MP157开发板上使用的就是16P的TypeC母座16P 的母座引脚结构如下图所示 上图就是16P的TypeC引脚示意图从左到右依次是1-16 脚注意1,2 脚、3,4 脚、13,14 脚和15,16脚离得很近看起来像是一个引脚其实他们是两个引脚。16P对应的引脚功能如下图所示 可以看出相比于标准24P引脚定义16P的母座少了8根USB3.1高速差分收发数据线。
USB TypeC的Data Role
USB2.0根据数据传输方向定义了HOST/Device/OTG这三种类型的设备角色其中OTG既可以做HOST也可以做DeviceUSB2.0的OTG设备接口通过ID线来区分HOST还是Device。在TypeC领域也有类似的概念但是名字变了
DFPDFP全称是Downstream Facing Port也就是下行端口可以理解为HOSTDFP提供VBUS、VCONN可以接收数据。UFPUFP全称是Upstream Facing Port也就是上行端口可以理解为DeviceUFP 从VBUS中取电源UFP设备也可以传输数据比如U盘键盘鼠标等。DRPDRP全称是Dual Role Port也就是双角色端口可以理解为OTGDRP既可以做DFP也可以做UFP。也可以在DFP和UFP之间进行动态切换。这个切换过程就用到了CC引脚具体识别过程比较复杂这里就不讲解了。如果要在USB TypeC接口上实现DRP功能那么就需要使用到外置的TypeC芯片正点原子STM32MP157开发板使用了STUSB1600或FUSB302MPX这两种TypeC芯片。这两种芯片都有一个IIC配置接口也就是需要编写驱动程序否则的话DRP功能无法实现。
硬件原理图分析
正点原子的STM32MP1开发板USB部分原理图可以分为两部分USB HUB以及USB OTG。
USB TypeC本来是给USB3.1准备的单位了方便使用所以正点原子STM32MP157开发板也使用了TypeC接口但是本质上还是USB2.0协议所以不要看到TypeC就以为支持USB3.0
另外使用TypeC接口实现OTG功能的话就需要外界TypeC芯片通过专用的TypeC芯片来控制CC引脚实现USB的主从切换。V1.3版本以前的底板使用STUSB1600这颗TypeC芯片V1.5版本以后的底板都使用FUSB302MPX。
依次来看一下这两部分的硬件原理图。
USB HUB原理图分析
首先来看一下USB HUB原理图STM32MP1使用FE2.1这个HUB芯片将STM32MP1的USB2扩展成了7路HOST接口其中一路供4G模块使用因此就剩下了6个通用的USB A插座原理图如下图所示 上图中U21就是USB HUB芯片FE2.1FE2.1是一款符合USB2.0标准的USB HUB芯片支持一拖七扩展可以将一路USB扩展为7路USB HOST接口。这里将STM32MP1的USB1扩展出了7路USB HOST接口分别为HUB_DP1/DM1、HUB_DP2/DM2、HUB_DP3/DM3、HUB_DP4/DM4、HUB_DP5/DM5、HUB_DP6/DM6和HUB_DP7/DM7。其中HUB_DP7/DM7用于4G模块因此对外提供的只有六个USB HOST接口这三个USB HOST接口如下图所示 注意使用FE2.1扩展出来的7路USB接口只能用作HOST
USB OTG原理图分析
正点原子的STM32MP1开发板上还有一路USB OTG接口使用STM32MP1的USB OTG接口。此路USB OTG既可以作为主机(HOST)也可以作为从机(DEVICE)从而实现完整的OTG功能。V1.4版本以前的底板上TypeC芯片使用STUSB1600V1.5及以后版本的底板使用FUSB302MPX这颗芯片。
现在购买的话都是V1.5以后的版本了开发板的USB OTG是使用FUSB302MPX做控制。原理图如下图所示 FUSB302PMX也是负责控制切换主机和从机模式的MT9700HT5是负载开关用来控制VBUS输出当OTG_PWR_CTRL输出高电平的时候OUT引脚就输出5V电压也就是VBUS变为5V。当OTG_PWR_CTRL输出低电平的时候OUT输出0V相当于VBUS关闭。
所以当开发板上的TypeC接口作为主设备的时候OTG_PWR_CTRL要输出高电平VBUS输出5V为外部USB设备供电。当TypeC接口作为从设备的时候OTG_PWR_CTRL输出低电平。OTG_PWR_CTRL对应的GPIO 引脚为PZ6。
USB协议简介
USB描述符
USB描述符就是用来描述USB信息的描述符就是一串按照一定规则构建的字符串USB设备使用描述符来向主机报告自己的相关属性信息常用的描述符如下图所示 依次来看一下上图中这5个描述符的含义。
设备描述符
设备描述符用于描述USB设备的一般信息USB设备只有一个设备描述符。设备描述符里面记录了设备的USB版本号、设备类型、VID(厂商 ID)、PID(产品 ID)、设备序列号等。设备描述符结构如下图所示 配置描述符
设备描述符的bNumConfigurations域定义了一个USB设备的配置描述符数量一个USB设备至少有一个配置描述符。配置描述符描述了设备可提供的接口(Interface)数量、配置编号、供电信息等配置描述符结构如下图所示 字符串描述符
字符串描述符是可选的字符串描述符用于描述一些方便阅读的信息比如制造商、设备名称等。如果一个设备没有字符串描述符那么其他描述符中和字符串有关的索引值都必须为0字符串描述符结构如下图所示 wLANGID[0]~wLANGID[x]指明了设备支持的语言 具体含义要查阅文档《USB_LANGIDs.pdf》。
主机会再次根据自己所需的语言向设备请求字符串描述符这次主机会指明要得到的字符串索引值和语言。设备返回Unicode编码的字符串描述符结构如下图所示 接口描述符
配置描述符中指定了该配置下的接口数量配置可以提供一个或多个接口接口描述符用于描述接口属性。接口描述符中一般记录接口编号、接口对应的端点数量、接口所述的类等接口描述符结构如下图所示 端口描述符
接口描述符定义了其端点数量端点是设备与主机之间进行数据传输的逻辑接口除了端点0是双向端口其他的端口都是单向的。端点描述符描述了树传输类型、方向、数据包大小、端点号等信息端点描述符结构如下图所示 USB数据包类型
USB是串行通信需要一位一位的去传输数据USB传输的时候先将原始数据进行打包所以USB中传输的基本单元就是数据包。根据用途的不同USB协议定义了4种不同的包结构令牌(Token)包、数据(Data)包、握手(Handshake)包和特殊(Special)包。这四种包通过包标识符PID来区分PID共有8位USB协议使用低4位PID3-PID0另外的高四位PID7-PID4是PID3-PID0的取反传输顺序是PID0、PID1、PID2、PID3…PID7。令牌包的PID1-0为01数据包的PID1-0 为11握手包的PID1-0为10特殊包的PID1-0为00。每种类型的包又有多种具体的包如下图所示 一个完整的包分为多个域所有的数据包都是以同步域(SYNC)开始后面紧跟着包标识符(PID)最终都以包结束(EOP)信号结束。不同的数据包中间位域不同一般有包目标地址(ADDR)、包目标端点(ENDP)、数据、帧索引、CRC等这个要具体数据包具体分析。接下来简单看一下这些数据包的结构。
令牌包
令牌包结构如下图所示 上图是一个SETUP令牌包结构首先是SYNC同步域包同步域为00000001也就是连续7个0后面跟一个1如果是高速设备的话就是31个0后面跟一个1。紧跟着是PID这里是SETUP包为0XB4是0XB4的原因如下
ETUP包的PID3-PID0 为1101因此对应的PID7~PID4就是0010。PID传输顺序为PID0、PID1、PID2…PID7因此按照传输顺序排列的话此处的PID就是101101000XB4并不是0X2D。
PID后面跟着地址域(ADDR)和端点(ENDP)为目标设备的地址和端点号。CRC5域是5位CRC值是ADDR和ENDP这两个域的校验值。最后就是包结束域(EOP)标记本数据包结束。其他令牌包的结构和SETUP基本类似只是SOF令包中间没有ADDR和ENDP这两个域而是只有一个11位的帧号域。
数据包
数据包结构如下图所示 数据包比较简单同样的数据包从SYNC同步域开始然后紧跟着是PID这里就是DATA0PID值为0XC3。接下来就是具体的数据数据完了以后就是16位的CRC校验值最后是EOP。
握手包
握手包结构如下图所示 上图是ACK握手包很简单首先是SYNC同步域然后就是ACK包的PID为0X4B最后就是EOP。其他的NAK、STALL、NYET和ERR握手包结构都是一样的只是其中的PID不同而已。
USB传输类型
在端点描述符中bmAttributes指定了端点的传输类型一共有4种本节来看一下这四种传输类型的区别。
控制传输
控制传输一般用于特定的请求比如枚举过程就是全部由控制传输来完成的比如获取描述符、设置地址、设置配置等。控制传输分为三个阶段建立阶段(SETUP)、数据阶(DATA)和状态阶段(STATUS)其中数据阶段是可选的。建立阶段使用SETUP令牌包SETUP使用DATA0包。数据阶段是 0 个、1个或多个输入(IN)/输出(OUT)事务数据阶段的所有输入事务必须是同一个方向的比如都为IN或都为OUT。数据阶段的第一个数据包必须是DATA1每次正确传输以后就在DATA0和DATA1之间进行切换。数据阶段完成以后就是状态阶段状态阶段的传输方向要和数据阶段相反比如数据阶段为IN的话状态阶段就要为OUT状态阶段使用DATA1包。比如一个读控制传输格式如下图所示 同步传输
同步传输用于周期性、低时延、数据量大的场合比如音视频传输这些场合对于时延要求很高但是不要求数据100%正确允许有少量的错误。因此同步传输没有握手阶段即使数据传输出错了也不会重传。
批量传输
批量传输就是用于大批量传输大块数据的这些数据对实时性没有要求比如MSD类设备(存储设备)U盘之类的。批量传输分为批量读(输入)和批量写(输出)如果是批量读的话第一阶段就是IN令牌包如果是批量写那么第一阶段就是OUT令牌包。
就以批量写为例简单介绍一下批量传输过程
主机发出OUT令牌包令牌包里面包含了设备地址、端点等信息。如果OUT令牌包正确的话也就是设备地址和端点号匹配主机就会向设备发送一个数据(DATA)包发送完成以后主机进入接收模式等待设备返回握手包一切都正确的话设备就会向主机返回一个ACK握手信号。
批量读的过程刚好相反
主机发出IN令牌包令牌包里面包含了设备地址、端点等信息。发送完成以后主机就进入到数据接收状态等待设备返回数据。如果IN令牌包正确的话设备就会将一个DATA包放到总线上发送给主机。主机收到这个DATA包以后就会向设备发送一个ACK握手信号。
中断传输
这里的中断传输并不是传统意义上的硬件中断而是一种保持一定频率的传输中断传输适用于传输数据量小、具有周期性并且要求响应速度快的数据比如键盘、鼠标等。中断的端点会在端点描述符中报告自己的查询时间间隔对于时间要求严格的设备可以采用中断传输。
USB枚举
当USB设备与USB主机连接以后主机就会对USB设备进行枚举通过枚举来获取设备的 描述符信息主机得到这些信息以后就知道该加载什么样的驱动、如何进行通信等。USB 枚举过程如下
第一回合当USB主机检测到USB设备插入以后机会发出总线复位信号来复位设备。USB设备复位完成以后地址为0主机向地址0的端点0发送数据请求设备的描述符。设备得到请求以后就会按照主机的要求将设备描述符发送给主机主机得到设备发送过来的设备描述符以后如果确认无误就会向设备返回一个确认数据包(ACK)。第二回合主机再次复位设备进入地址设置阶段。主机向地址0的端点0发送设置地址请求数据包新的设备地址就包含在这个数据包中因此没有数据过程。设备进入状态过程等待主机请求状态返回收到以后设备就会向主机发送一个0字节状态数据包表明设备已经设置好地址了主机收到这个0字节状态数据包以后会返回一个确认包(ACK)。设备收到主机发送的ACK包以后就会使用这个新的设备地址至此设备就得到了一个唯一的地址。第三回合主机向新的设备地址端点0发送请求设备描述符数据包这一次主机要获取整个设备描述符一共是18个字节。和第3步类似接下来依次获取配置描述符、配置集合、字符串描述符等等。
STM32MP1 USB HOST驱动编写
接下来就开始编写USB HOST的驱动。USB子系统是一个标准和复杂的接口所以驱动基本不用写都是内核里有现成的只需要在设备树提供对应的设备节点即可。
之前的学习有说到USBH是只能主机模式要编写USB HOST就用USBH控制器即可。ST官方的STM3MP157C-DK2开发板已经配置好了USBH的节点信息所以直接参考此节点即可这样开发板就能够使用 USB Host 模式。
USBH控制器节点信息
打开“stm32mp151.dtsi”文件找到USBH两个控制器的节点信息名字分别为“usbh_ohci”和“usbh_ehci”。如下示例代码所示
示例代码 50.4.1 USBH 下两个控制器节点信息
1 usbh_ohci: usbh-ohci5800c000 {
2 compatible generic-ohci;
3 reg 0x5800c000 0x1000;
4 clocks rcc USBH;
5 resets rcc USBH_R;
6 interrupts GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH;
7 status disabled;
8 };
9
10 usbh_ehci: usbh-ehci5800d000 {
11 compatible generic-ehci;
12 reg 0x5800d000 0x1000;
13 clocks rcc USBH;
14 resets rcc USBH_R;
15 interrupts-extended exti 43 IRQ_TYPE_LEVEL_HIGH;
16 companion usbh_ohci;
17 power-domains pd_core;
18 wakeup-source;
19 status disabled;
20 };从上面的代码可以知道USBH是支持USB2.0和USB1.1的。使用USB2.0就要配置usbh_ehci节点使用USB1.1就要配置usbh_ohci 节点。这两个节点的信息是不需要修改的这是STM32MP1一些通用配置信息。需要做的就是在stm32mp157d-atk.dts文件中追加对应属性信息然后status属性值改为“okay”还要配置USBH使用哪个PHY端口。根据两个节点的compatible属性找到对应的驱动路径为drivers/usb/host/ohci-platform.c和drivers/usb/host/ehci-platform.c。
配置PHY控制器
先了解一下PHY控制器一些通用配置打开 stm32mp151.dtsi文件找的如下内容所示
示例代码 50.4.2 usbphyc 控制器节点信息
1 usbphyc: usbphyc5a006000 {
2 #address-cells 1;
3 #size-cells 0;
4 #clock-cells 0;
5 compatible st,stm32mp1-usbphyc;
6 reg 0x5a006000 0x1000;
7 clocks rcc USBPHY_K;
8 resets rcc USBPHY_R;
9 vdda1v1-supply reg11;
10 vdda1v8-supply reg18;
11 status disabled;
12
13 usbphyc_port0: usb-phy0 {
14 #phy-cells 0;
15 reg 0;
16 };
17
18 usbphyc_port1: usb-phy1 {
19 #phy-cells 1;
20 reg 1;
21 };
22 };示例代码50.4.1.2 usbphyc节点就是STM32MP1的USB PHY。已经知道PHY控制器有两个端口刚好usbphyc节点里有两个子节点名字分别为usbphyc_port0和usbphyc_port1这两个子节点就是PHY控制器的两个端口其中usbphyc_port0只能分配给USB Host。注意“#phy-cells”属性和“#gpio-cells”属性作用是一样的如果#phy-cells为1表示一个cell此cell表示端口做USBH的PHY端口还是OTG的PHY端口0表示做OTG的PHY端口1表示做USBH的PHY端口。
打开“stm32mp15xx-dkx.dtsi”文件找到“usb_phy_tuning”节点把此节点的内容拷贝到stm32mp157d-atk.dts的根目录下拷贝内容如下所示
示例代码 50.4.3 添加的 usb_phy_tuning 节点信息
1 usb_phy_tuning: usb-phy-tuning {
2 st,hs-dc-level 2;
3 st,fs-rftime-tuning;
4 st,hs-rftime-reduction;
5 st,hs-current-trim 15;
6 st,hs-impedance-trim 1;
7 st,squelch-level 3;
8 st,hs-rx-offset 2;
9 st,no-lsfs-sc;
10 };usb_phy_tuning此节点负责调整PHY的配置对于此节点的属性内容感兴趣的可以去看Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.yaml文件 。 接着还是在stm32mp157d-atk.dts文件中使能usbphyc以及向usbphyc_port0节点追加的内容要修改的如下所示
示例代码 50.4.4 使能 usbphyc 和追加 usbphyc_port0 的内容
1 usbphyc {
2 status okay;
3 };
4
5 usbphyc_port0 {
6 phy-supply v3v3;
7 st,phy-tuning usb_phy_tuning;
8 };第2行这里把usbphyc的status属性修改为“okay”使能usbphyc。
第6行给usbphyc_port0节点追加phy-supply属性添加一个电源管理属性。
第7行把要修改的PHY配置添加到usbphyc_port0节点里。
配置usbh_ehci
最后在stm32mp157d-atk.dts文件使能usbh_ehci和指定PHY端口。
示例代码 50.4.5 追加 usbh_ehci 节点内容
1 usbh_ehci {
2 phys usbphyc_port0;
3 status okay;
4 };这里的内容很简单就是修改status属性为“okay”和指定使用usbphyc_port0端口。修改完就重新编译设备树使用新的stm32mp157d-atk.dtb设备树重新启动开发板。就会有以下输出所示 如果有上图这些输出信息说明usb host驱动加载到内核了。
Linux内核自带Host实验
USB鼠标键盘测试
首先做一下USB HOST试验也就是正点原子的STM32MP1开发板做USB主机然后外接USB设备比如USB鼠标键盘、USB 转TTL串口线、U盘等设备。Linux内核已经集成了大量的USB设备驱动尤其是常见的USB鼠标键盘、U盘等本节就来学习一下如何使能Linux内核常见的USB设备驱动。
USB鼠标键盘驱动使能
USB鼠标键盘属于HID设备内核已经集成了相应的驱动ST官方提供的linux内核默认已经使能了USB鼠标键盘驱动但是还要学习一下如何手动使能这些驱动。输入“make menuconfig”打开linux内核配置界面首先打开HID驱动按照如下路径到相应的配置项目 - Device Drivers - HID support - HID bus support - * Generic HID driver //使能通用 HID 驱动
使能后结果如下图所示 接下来需要使能USB键盘和鼠标驱动配置路径如下 - Device Drivers - HID support - USB HID support - * USB HID transport layer //USB 键盘鼠标等 HID 设备驱动
使能后如下图所示 可以将光标放到上图中“USB HID Transport layer”这一行然后按下“?”键打开对应的帮助信息就可以看到对于这个配置项的描述简单总结一下
此选项对应配置项就是CONFIG_USB_HID也就是USB接口的HID设备。如果要使用USB接口的keyboards(键盘)、mice(鼠标)、joysticks(摇杆)、graphic tablets(绘图板)等其他的HID设备那么就需要选中“USB HID Transport layer”。但是要注意一点此驱动和HIDBP(Boot Protocol)键盘、鼠标的驱动不能一起使用所以要是在网上查阅linux内核USB键盘鼠标驱动的时候发现推荐使用“USB HIDBP Keyboard (simple Boot) support”和“USB HIDBP Mouse (simple Boot) support”这两个配置项的时候也不要觉得教程这里写错了。
测试USB鼠标和键盘
完成以后重新编译linux内核并且使用得到的 uImage启动开发板。启动以后插入USB鼠标会有如下图所示的提示信息 从上图可以看出系统检测到了鼠标如果成功驱动的话就会在/dev/input目录下生成一个名为eventX(X0,1,2,3…)的文件这个就是前面讲的输入子系统鼠标和键盘都是作为输入子系统设备的。教程中这里对应的就是/dev/input/event1这个设备使用如下命令查看鼠标的原始输入值结果如下图 上图就是鼠标作为输入子系统设备的原始输入值这里就不去分析了在移植GUI图形库以后就可以直接使用鼠标比如QT等。
最后再来测试一下USB键盘屏幕已经驱动起来了所以可以直接将屏幕作为终端然后接上键盘直接输入命令来进行各种操作。首先将屏幕设置为控制台打开开发板根文件系统中的/etc/inittab文件然后在里面加入下面这一行 tty1::askfirst:-/bin/sh
完成以后重启开发板此时屏幕就会作为终端控制台会有“Please press Enter to activate this console.”这样提示如下图所示 接上键盘然后根据上图中的提示按下键盘上的Enter(回车)键即可使能LCD屏幕控制台然后就可以输入各种命令来执行相应的操作如下图所示 U盘实验
ST提供的Linux内核默认也已经使能了U盘驱动因此可以直接插上去使用。但是还是需要学习一下如何手动配置Linux内核使能U盘驱动。
使能U盘驱动
U盘使用SCSI协议因此要先使能Linux内核中的SCSI协议配置路径如下 - Device Drivers - SCSI device support - * SCSI disk support //选中此选项
结果如下图所示 还需要使能USB Mass Storage也就是USB 接口的大容量存储设备配置路径如下 - Device Drivers - USB support - USB Gadget Support - USB Gadget functions configurable through configfs - [*] Mass storage //选中
结果如下图所示 U盘测试
准备好一个U盘注意U盘要为FAT32格式的NTFS和exFAT由于版权问题所以在Linux下支持的不完善操作的话可能会有问题比如只能读不能写或者无法识别等。准备好以后将U盘插入到开发板USB HUB扩展出来的HOST接口上此时会输出如下图所示信息 从上图可以看出系统检测到U盘插入大小为16GB对应的设备文件为/dev/sda和/dev/sda1可以查看一下/dev目录下有没有sda和sda1这两个文件。/dev/sda是整个U盘/dev/sda1是U盘的第一个分区一般使用U盘的时候都是只有一个分区。要想访问U盘需要先对U盘进行挂载理论上挂载到任意一个目录下都可以这里可以创建一个/mnt/usb_disk目录然后将U盘挂到/mnt/usb_disk目录下命令如下 mkdir /mnt/usb_disk -p //创建目录 mount /dev/sda1 /mnt/usb_disk/ -t vfat -o iocharsetutf8 //挂载
-t指定挂载所使用的文件系统类型这里设置为vfat也就是FAT文件系统“-o iocharset” 设置硬盘编码格式为utf8否则的话U盘里面的中文会显示乱码
挂载成功以后进入到/mnt/usb_disk目录下输入ls命令查看U盘文件如下图所示 至此U盘就能正常读写操作了直接对/mnt/usb_disk目录进行操作就行了。如果要拔出U盘要执行一个sync命令进行同步然后在使用unmount进行U盘卸载命令如下所示 sync //同步 cd / //如果处于/mnt/usb_disk 目录的话先退出来否则卸载的时候提示设//备忙导致卸载失败切记 umount /mnt/usb_disk //卸载
Linux内核自带USB OTG实验
STUSB1600设备树编写
STUSB1600是ST出的一款TypeC 芯片也是ST官方开发板搭配STM32MP1的。STUSB1600的驱动设备树编写参考文档“Documentation/devicetree/bindings/usb/st,typec-stusb.txt”。此文档描述了STUSB1600 设备相关信息。
USB OTG控制器节点信息
进入到Linux内核源码目录打开arch/arm/boot/dts/stm32mp151.dtsi 设备树文件在这个设备树文件有一个usbotg_hs节点此节点就是USB OTG控制器节点内容如下
示例代码 50.6.1.1 usbotg_hs 控制器
1 usbotg_hs: usb-otg49000000 {
2 compatible st,stm32mp1-hsotg, snps,dwc2;
3 reg 0x49000000 0x10000;
4 clocks rcc USBO_K;
5 clock-names otg;
6 resets rcc USBO_R;
7 reset-names dwc2;
8 interrupts-extended exti 44 IRQ_TYPE_LEVEL_HIGH;
9 g-rx-fifo-size 512;
10 g-np-tx-fifo-size 32;
11 g-tx-fifo-size 256 16 16 16 16 16 16 16;
12 dr_mode otg;
13 usb33d-supply usb33;
14 power-domains pd_core;
15 wakeup-source;
16 status disabled;
17 };示例代码50.6.1.1中的usbotg_hs节点不需要修改这里只是查看一下usbotg_hs完整节点信息。根据第2行的compatible属性就是可以找到STM32MP1的usbotg_hs驱动源文件驱动文件名为drivers/usb/dwc2/params.c。第12行dr_mode属性用来配置控制器做otg功能还是host功能不配置此属性默认为otg功能。第16行的status属性为disabled所以usbotg_hs默认关闭的如果要使能就是要修改status属性为 okay、配置一个PHY端口和设置使用那个控制器去控制usbotg_hs。
使能usbotg_hs节点
首先先去配置PHY接口在stm32mp157d-atk.dts文件中追加usbphyc_port1节点内容如下所示
示例代码 50.6.1.2 usbphyc_port1 节点配置
1 usbphyc_port1 {
2 phy-supply vdd_usb;
3 st,phy-tuning usb_phy_tuning;
4 };注意要先使能usbphyc节点这里在USB HOST实验已经使能就不用配置。
接着去追加usbotg_hs的相关属性信息。追加的内容如下所示
示例代码 50.6.1.3 usbotg_hs 节点内容
1 usbotg_hs {
2 phys usbphyc_port1 0;
3 phy-names usb2-phy;
4 usb-role-switch;
5 status okay;
6
7 port {
8 usbotg_hs_ep: endpoint {
9 remote-endpoint con_usbotg_hs_ep;
10 };
11 };
12 };第2行配置usbotg_hs的PHY接口这里0表示为OTG USB的PHY端口。
第5行把status属性改为okay使能usbotg_hs。
第7-11行添加了一个port节点第9行指定usbotg_hs 节点使用con_usbotg_hs_ep做控制器con_usbotg_hs_ep会在STUSB1600节点里创建。
最后还需要添加vdd_usb电源节点因为示例代码50.6.1.2中的usbphyc_port1节点需要用到vdd_usb节点在stm32mp157d-atk.dts中添加vdd_usb电源节点在根节点下添加内容如下
示例代码 50.6.1.4 vdd_usb 电源节点
1 vdd_usb: regulator-vdd-usb {
2 compatible regulator-fixed;
3 regulator-name vdd_usb;
4 regulator-min-microvolt 3300000;
5 regulator-max-microvolt 3300000;
6 regulator-always-on;
7 regulator-boot-on;
8 };使能I2C1节点
控制Typec的芯片是STUSB1600此芯片是使用I2C协议和CPU进行通讯所以要使能I2C1。把示例代码50.6.1.4拷贝到stm32mp157d-atk.dts文件里代码如下所示
示例代码 50.6.1.5 使能 i2c1 节点
1 i2c1 {
2 pinctrl-names default, sleep;
3 pinctrl-0 i2c1_pins_b;
4 pinctrl-1 i2c1_pins_sleep_b;
5 status okay;
6 };正点原子STM32MP157开发板I2C1_SCL和I2C1_SDA这两个引脚为PF14和PF15。这两个引脚的pinctrl配置已经在stm32mp15-pinctrl.dtsi文件里面提供了如果使用的其他引脚需要自行配置。
配置STUSB1600节点
先配置STUSB1600的中断引脚电气属性和电源管理STUSB1600中断引脚为PG2在stm32mp15-pinctrl.dtsi文件中输入如下内容
示例代码 50.6.1.6 stusb1600 中断电气属性
1 stusb1600_pins_b: stusb1600-0 {
2 pins {
3 pinmux STM32_PINMUX(G, 2, ANALOG);
4 bias-pull-up;
5 };
6 };把STUSB1600的中断引脚改为内部上拉。因为USB OTG需要5V电源管理前面没有此配置所以要一个5V的电源配置在根节点下添加如下示例代码所示
示例代码 50.6.1.7 5V 的 vin 节点
1 vin: regulator-vin {
2 compatible regulator-fixed;
3 regulator-name vin;
4 regulator-min-microvolt 5000000;
5 regulator-max-microvolt 5000000;
6 regulator-always-on;
7 regulator-boot-on;
8 };接下来配置STUSB1600节点此节点属于I2C1的子节点。STUSB1600的配置内容如下所示
示例代码 50.6.1.8 stusb1600 节点信息
1 stusb160028 {
2 compatible st,stusb1600;
3 reg 0x28;
4 interrupts 2 IRQ_TYPE_EDGE_FALLING;
5 interrupt-parent gpiog;
6 pinctrl-names default;
7 pinctrl-0 stusb1600_pins_b;
8 status okay;
9 vdd-supply vin;
10
11 connector {
12 compatible usb-c-connector;
13 label USB-C;
14 power-role dual;
15 power-opmode default;
16
17 port {
18 con_usbotg_hs_ep: endpoint {
19 remote-endpoint usbotg_hs_ep;
20 };
21 };
22 };
23 };示例代码50.6.1.7代码中可以分为两个部分第1-9行属于控制STUSB1600芯片相关属性第11-22行属于Typec端口相关属性。
第2行compatible的属性值为“st,stusb1600”在Linux源码目录下搜索此属性值会找到stusb1600的驱动源码为drivers/usb/typec/typec_stusb.c。
第3行reg属性值为“0x28”stusb1600芯片通讯地址为0x28。
第4-5行设置中断相关配置中断触发为下降沿触发。
第6-7行设置中断的电气属性。
第9行设置电源配置。
第12-15行可以查看Documentation/devicetree/bindings/connector/usb-connector.txt 文件。
第17-20行定义了一个con_usbotg_hs_ep端口同时指定此端口连接到usbotg_hs节点的usbotg_hs_ep端口。
重新编译设备树使用新的stm32mp157d-atk.dtb 文件去启动开发板。
FUSB302驱动移植
在上一小节已经完成了一部分的设备树配置由于只是改了USB TypeC的芯片所以只需要把STUSB1600相关的部分改为FUSB302 即可。其实就是上一小节前面的1-3小点不用修改只需要改第4小点。
首先配置FUSB302的中断电气属性配置如下所示
示例代码 50.6.2.1 fusb302 中断电气属性
1 fusb302_pins_a: fusb302-0 {
2 pins {
3 pinmux STM32_PINMUX(G, 2, ANALOG);
4 bias-pull-up;
5 };
6 };在 stm32mp157d-atk.dts文件中添加头文件“dt-bindings/usb/pd.h”如下图所示 接着配置FUSB302节点配置的代码如下所示
示例代码 50.6.2.2 fusb302 节点信息
1 fusb30222 {
2 compatible fcs,fusb302,fairchild,fusb302;
3 reg 0x22;
4 pinctrl-names default;
5 pinctrl-0 fusb302_pins_a;
6 int-n-gpios gpiog 2 GPIO_ACTIVE_HIGH;
7 vbus-5v-gpios gpioz 6 GPIO_ACTIVE_HIGH;
8 status okay;
9
10 connector {
11 compatible usb-c-connector;
12 label USB-C;
13 power-role dual;
14 power-opmode default;
15
16 try-power-role sink;
17 source-pdos PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM);
18 sink-pdos PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)
19 PDO_VAR(3000, 12000, 3000)
20 PDO_PPS_APDO(3000, 11000, 3000);
21 op-sink-microwatt 10000000;
22 port {
23 con_usbotg_hs_ep: endpoint {
24 remote-endpoint usbotg_hs_ep;
25 };
26 };
27 };
28 };fusb302的设备树没有使用电源管理而是用PZ6 引脚去控制电压。其它的属性和stusb1600一样。
最后就是去改驱动了Linux内核提供的fusb302驱动是没读取connector相关的属性所以此驱动是不能使用。在github里找到了可用的fusb302驱动改动的部分是如何读取connector节点和使用PZ6引脚控制电压。想看如何修改的可以用文件对比软件就能知道修改了那些内容。将25_fusb302目录的fusb302.c和fusb302.h文件拷贝到linux源码下的drivers/usb/typec/tcpm目录里注意要把原来的fusb302.c覆盖掉拷贝结果如下图所示 拷贝完成后进入内核的配置选项图形界面配置路径如下 - Device Drivers - USB support - USB Type-C Support - USB Type-C Port Controller Manager - * Fairchild FUSB302 Type-C chip driver //选中
如下图所示 重新编译设备树和内核使用新的设备树stm32mp157d-atk.dtb和内核uImage去启动开发 板有如下图打印信息说明加载驱动成功。如图所示 OTG主机实验
系统重启成功以后就可以正常使用USB_OTG接口OTG既可以做主机也可以做从机做主机的话测试方法和之前的测试一模一样直接在正点原子的USB_OTG接口上使用Typec OTG线接入鼠标键盘、U盘等设备。USB_OTG接口如下所示 OTG从机实验
OTG从机就是将开发板作为一个USB设备连接到其他的主机上这里来做两个USB从机实验模拟U盘以及USB声卡。
模拟U盘实验
模拟U盘实验就是将开发板当做一个U盘可以将开发板上的U盘或者TF卡挂载到PC上首先需要配置Linux配置路径如下 - Device Drivers - USB support - USB Gadget Support - USB Gadget functions configurable through configfs //不要编译进内核 - USB Gadget precomposed configurations ( [m]) - Mass Storage Gadget //大容量存储
结果如下图所示 这里需要将驱动编译为模块使用的时候直接输入命令加载驱动模块即可。配置好 以后执行下面这些命令重新编译Linux内核、编译模块 make uImage LOADADDR0XC2000040 -j32 make modules -j32
编译完成后会得到3个.ko内核模块文件对应路径为 drivers/usb/gadget/libcomposite.ko drivers/usb/gadget/function/usb_f_mass_storage.ko drivers/usb/gadget/legacy/g_mass_storage.ko
将上述三个.ko 模块拷贝到开发板根文件系统/lib/modules/5.4.31目录下如图所示 拷贝完成以后使用新编译出来的uImage启动开发板在开发板上插入一个U盘记住这个U盘对应的设备文件比如这里是/dev/sda 和/dev/sda1以后要将/dev/sda1挂载到PC上也就是把/dev/sda1作为模拟U盘的存储区域。
使用TypeC数据线将开发板和电脑连接连接好以后依次加载libcomposite.ko、usb_f_mass_storage.ko和g_mass_storage.ko这三个驱动文件顺序不能错了命令如下 depmod modprobe libcomposite.ko modprobe usb_f_mass_storage.ko modprobe g_mass_storage.ko file/dev/sda1 removable1
加载g_mass_storage.ko的时候使用file参数指定使用的大容量存储设备这里使用U盘对应的/dev/sda1。如果加载成功的话电脑就会出现一个U盘这个U盘就是开发板模拟的可以直接在电脑上对这个U盘进行读写实际上就是操作插在开发板上的U盘。操作完成后要退出需要执行如下命令 rmmod g_mass_storage.ko rmmod usb_f_mass_storage.ko rmmod libcomposite.ko
注意不要将开发板上的EMMC或者NAND作为模拟U盘的存储区域因为linux下EMMC和NAND使用的文件系统一般都是EXT3/EXT4和UBIFS这些文件系统类型和windows下的不兼容如果挂载的话就会在windows下提示要格式化U盘
USB声卡实验
USB声卡就是USB接口的外置声卡一般电脑内部都自带了声卡但是内部自带的声卡效果相对来说比较差不能满足很多HIFI玩家的需求。USB声卡通过USB接口来传递音频数据具体的ADC和DAC过程由声卡完成摆脱了电脑主板体积的限制外置USB声卡就可以做的很好。STM32MP1开发板板载了音频解码芯片因此可以将STM32MP1开发板作为一个外置USB声卡配置Linux内核配置路径如下 - Device Drivers - USB suppor - USB Gadget Support - USB Gadget precomposed configurations - Audio Gadget //选中音频编译为模块 - UAC 1.0 //选中 - [*] UAC 1.0 (Legacy) //选中 UAC
配置如下图所示 注意这里也是编译为驱动模块配置完成以后重新编译内核、编译模块会得到3个驱动模块文件模块文件路径如下 drivers/usb/gadget/libcomposite.ko drivers/usb/gadget/function/usb_f_uac1_legacy.ko drivers/usb/gadget/legacy/g_audio.ko
将上述三个.ko模块文件拷贝到开发板根文件系统/lib/modules/5.4.31目录下拷贝完成以后使用新编译出来的uImage启动开发板首先要按照之前学习的音频驱动的方法配置STM32MP1的声卡保证声卡播放正常使用Typec数据线将开发板与电脑连接起来最后依次加载 libcomposite.ko、usb_f_uac1_legacy.ko和g_audio.ko这三个驱动模块命令如下 depmod modprobe libcomposite.ko modprobe usb_f_uac1_legacy.ko modprobe g_audio.ko
加载完成以后稍等一会虚拟出一个USB声卡打开电脑的设备管理器选择“声音、视频和游戏控制器”会发现有一个名为“AC Interface”设备如下图所示 上图中的“AC Interface”就是开发板模拟出来的USB声卡设置Windows选择音频输出使用“AC Interface”Windows10设置如下图所示 一切设置好以后就可以从开发板上听到电脑输出的声音此时开发板就完全是一个USB声 卡设备了。
关于USB驱动就讲解到这里本章并没有深入到USB驱动具体编写方式只是对USB的协议做了简单的介绍后面讲解了一下Linux内核自带的USB HOST和DEVICE驱动的使用Linux 内核已经集成了大量的USB设备驱动至于其他特殊的就需要具体情况具体分析了。
总结
本章的学习重点主要就是对USB设备做了一个大致的了解然后对USB的传输协议大致做了介绍这一部分可以多看看如果之后想做项目有要用到USB设备的话这一部分要多琢磨一下。
然后就是具体的STM32MP157开发板的USB驱动的使用。
对于USB HOST来说这一部分需要在设备树中(.dts)在根节点下添加usb_phy_tuning节点(可以直接从stm32mp15xx-dkx.dtsi复制)然后在设备树中添加usbphyc和usbphyc_port0的节点之后在添加usbh_ehci节点。
以上就配置完成了之后要具体使用USB驱动设备的话就进入Linux内核里面取使能对应设备就可以了。
至于USB OTG的驱动因为我这边新买的肯定是最新的就是FUSB302芯片。在设备树里面追加usbphyc_port1节点然后再加一个usbotg_hs节点然后在根节点加上usbphyc_port1所需要的vdd_usb节点之后添加i2c1节点并使能最后配置fusb302的电气属性在i2c1节点下添加fusb302节点。最后再修改一下驱动把提供的驱动文件拷贝到drivers/usb/typec/tcpm目录里面最后进入内核配置使能FUSB302配置就可以了。
OTG主机实验和HOST是一样的从机就需要先进入内核配置使能然后需要“make modules”并按照前面写的复制.ko到/lib/modules/5.4.31然后按照顺序来modprobe最后不用了就rmmod就可以了。