1、STM32_USB硬件模块简介
首先对STM32系列MCU自带的USB模块有一个概念性的认知,官方提供的培训PPT写的也很清晰,如下。

我们下面所说的全部都是F103系列的USB_FS.
在STM32F10X参考手册里面有如下两段话。

除了对USB硬件模块有了一个最基本的说明外,需要注意的就是有以下三点。
● F103系列的MCU里面CAN和USB模块不能同时使用(F105,F107不受该影响)
● USB的ACK包的发送和ACK包的处理,令牌包分组的检测,数据的发送和接收,包括USB里面的CRC校验,全部都由硬件自动做完了。
● 一共8个双向端点,可以作为16个单向端点使用
除此之外,USB提供低功耗模式(不产生任何静态电流,USB时钟减慢或停止)。
2、STM32_USB硬件功能框图

各个功能框图的描述其实在ST官方的培训文档也说的很详细了,如下所示。

3、STM32_USB硬件中断
USB模块的寄存器主要分为三大类,在手册里面也说了。

先看一下通用寄存器里面最简单的两个寄存器。这部分基本没啥说的,和STM32其他模块大同小异。
寄存器功能描述
BTABLE寄存器里面存放了缓冲区描述表的起始地址
DADDR寄存器 1、USB模块的总开关
2、记录了HOST设置的设备地址
下面的两个寄存器都是和中断相关的。
● CNTR寄存器

● ISTR寄存器

可以很清晰的看到CNTR里面存放着USB中断的使能位,在这里我们只需要关注ISTR的CTR、WKUP、SUSP和RESET这4个bit即可。
[tr]中端标志位描述[/tr][tr]CTR[td]每次传输完成后都会触发这个标志位[tr]WKUP[td]只有在挂起的时候检测到总线的复位信号才会触发[tr]SUSP[td]总线无信号后,硬件自动挂起[tr]RESET[td] 检测到复位信号后触发,触发后USB模块的发送和接收将会被禁止,直至此为被清除
4、STM32_USB端点相关寄存器
端点寄存器的数量由USB模块所支持的端点数目决定。每个端点都有与之对应的USB_EpnR寄存器,用于存储该端点的各种状态信息。比如F1系列一共有8个双向端点, 则0≤n≤7.具体寄存器内容如下。

这个寄存器中有 4 类标志,分别是只能清零( rc_w0),写1 翻转(t),只读( r),读写( rw)。
rc_w0 写1无效,写0清0
t 写1翻转,写0无变化
主要关注下表的几个寄存器。
位名称含义
CTR_RX正确接收到OUT或SETUP分组时由硬件置位,如果CTRM被置位,产生对应中断,以NAK或者STALL结束的分组和出错不会导致该位置位。
STAT_RX[1:0]指示端点当前状态

EP_TYPE[1:0]

CTR_TX正确传输一个IN分组时由硬件置位,如果CTRM被置位,产生对应中断.IN分组传输完成后,如果主机响应NAK或STALL,则不会被置位。
STAT_TX[1:0]指示发送数据的状态位

DEVICE库
4、PMA读写
在开始的时候就提到过PC和USB的交互是通过一段专属的数据缓冲区进行的,该数据缓冲区在硬件功能框图里面又被叫做Packet Buffer Memory,该区域在ST官方的USB库里面又被叫做Packet Memory Area,简称PMA.那么我们如何和这段内存进行交互呢?
首先从上面的信息里面可以知道,PMA的大小是512字节,可以通过APB1总线/USB控制器访问,且APB1的访问权限要高于USB.且软件部分通过Packet buffer interface访问(管理)PMA的存储空间,我们想使用的packet buffer的位置和大小可以随意配置,由buffer描述表指定。
buffer描述表,这个东西实在难理解,首先要明白,它本身也是占用内存的,且占用的内存也在PMA区域里面,但是这块内存的地址是由USB_BTABLE寄存器指定的!!!如下所示。

可以看到这个寄存器的功能只有一个,那就是保存了buffer描述表的起始地址。
通过上面的几段话,可以明白,想要操作这段内存空间(Packet Buffer Memory)就要对buffer描述表进行操作,但buffer描述表本身就处于这段内存中。那该如何操作这个描述表呢?这个描述表的大小又如何确定?
4.1、操作描述表
首先来看如何操作这个描述表,下面看官方提供的一段描述。

简单点说,这个描述表本身可以看成寄存器,使用操作寄存器的收发去操作。下面看一段官方的代码。
可以很清楚的看到,_wRegVal其实就是你要操作的ADDR_TX/RX的地址,这两段代码就是设置TX/RX缓冲区的起始地址。
这个时候已经设置好了数据存放的地址点了,但是数据交互的长度还没有设置,同理,如下所示。

其实也没什么好说的,就是根据数据量的不同,对寄存器进行设定,只是运算方法比较巧妙,有兴趣可以自己琢磨琢磨。
4.2、描述表大小的确定
上面说完了如何操作描述表,让我们可以自由的设定发送和接收的地址缓冲区和长度了,但如何确定你要使用的缓冲区地址呢,毕竟我要用的缓冲区和描述表是出于同一段内存空间的。下面看一张图。

有了上面的知识,应该已经知道能大概理解这张图的含义了,可以看出每个端点所使用的描述表大的大小为8个字节,简单点理解
描述表大小 = MAN_EP_NUM*8
结合例子,可以看到端点0的地址设定的是0X18(24),意思就是前24个字节用于缓冲区描述符,后续的各项间隔为0X40,其实就是端点描述符中的wMaxPacketSize.
其实我挺好奇的,复合设备的端点用的是0、1、2的双向端点,3的单向端点,其实按道理来说这地方应该是0X20,但是依旧能正常使用,后来经过实际测试,发现在通讯过程的并没有CDC_CMD_EP的传输数据。所以只使用了0,1,2三个端点。所以这个地方还是可以正常使用的。
建议使用端点的时候最好使用连续的端点,如果使用的是0,1,3.计算的时候还是需要按照4个端点进行计算的,端点2虽然没有使用,但是在实际的内存空间里面还是有端点2的描述表的。这样的话就会有空间浪费。
下面说一些我整了半天才整明白的概念,可能有点简单,但是我确实很迷。

简单说一下,USB_EPnR寄存器的低四位是专门存储端点地址的,比如我们在EP1R的寄存器里面写入0X0A,那么我们代码里面使用的EP1的实际地址就是0X0A,那么如果你的实际端点号其实是0X0A,但是在代码层面8个端点被抽象成为了IN_ep[8],调用的时候使用IN_ep[1]操作的依然是0X0A端点,实现了对底层的抽象。

还有就是一直说STM32有8个双向端点,可以作为16个单向端点使用,我被这句话迷惑了好久,明明只有8个EPnrR寄存器,为什么可以使用16个单向端点,后来在上述图片内看到这句话,才明白,USB_IP最多只能使用8个端点,也就是说,我们不能同时使用15个IN/OUT端点。
他说的这16个单向端点受EPnR控制,说的就是受上图红框内的寄存器位控制。
1、STM32_USB硬件模块简介
首先对STM32系列MCU自带的USB模块有一个概念性的认知,官方提供的培训PPT写的也很清晰,如下。

我们下面所说的全部都是F103系列的USB_FS.
在STM32F10X参考手册里面有如下两段话。

除了对USB硬件模块有了一个最基本的说明外,需要注意的就是有以下三点。
● F103系列的MCU里面CAN和USB模块不能同时使用(F105,F107不受该影响)
● USB的ACK包的发送和ACK包的处理,令牌包分组的检测,数据的发送和接收,包括USB里面的CRC校验,全部都由硬件自动做完了。
● 一共8个双向端点,可以作为16个单向端点使用
除此之外,USB提供低功耗模式(不产生任何静态电流,USB时钟减慢或停止)。
2、STM32_USB硬件功能框图

各个功能框图的描述其实在ST官方的培训文档也说的很详细了,如下所示。

3、STM32_USB硬件中断
USB模块的寄存器主要分为三大类,在手册里面也说了。

先看一下通用寄存器里面最简单的两个寄存器。这部分基本没啥说的,和STM32其他模块大同小异。
寄存器功能描述
BTABLE寄存器里面存放了缓冲区描述表的起始地址
DADDR寄存器 1、USB模块的总开关
2、记录了HOST设置的设备地址
下面的两个寄存器都是和中断相关的。
● CNTR寄存器

● ISTR寄存器

可以很清晰的看到CNTR里面存放着USB中断的使能位,在这里我们只需要关注ISTR的CTR、WKUP、SUSP和RESET这4个bit即可。
[tr]中端标志位描述[/tr][tr]CTR[td]每次传输完成后都会触发这个标志位[tr]WKUP[td]只有在挂起的时候检测到总线的复位信号才会触发[tr]SUSP[td]总线无信号后,硬件自动挂起[tr]RESET[td] 检测到复位信号后触发,触发后USB模块的发送和接收将会被禁止,直至此为被清除
4、STM32_USB端点相关寄存器
端点寄存器的数量由USB模块所支持的端点数目决定。每个端点都有与之对应的USB_EpnR寄存器,用于存储该端点的各种状态信息。比如F1系列一共有8个双向端点, 则0≤n≤7.具体寄存器内容如下。

这个寄存器中有 4 类标志,分别是只能清零( rc_w0),写1 翻转(t),只读( r),读写( rw)。
rc_w0 写1无效,写0清0
t 写1翻转,写0无变化
主要关注下表的几个寄存器。
位名称含义
CTR_RX正确接收到OUT或SETUP分组时由硬件置位,如果CTRM被置位,产生对应中断,以NAK或者STALL结束的分组和出错不会导致该位置位。
STAT_RX[1:0]指示端点当前状态

EP_TYPE[1:0]

CTR_TX正确传输一个IN分组时由硬件置位,如果CTRM被置位,产生对应中断.IN分组传输完成后,如果主机响应NAK或STALL,则不会被置位。
STAT_TX[1:0]指示发送数据的状态位

DEVICE库
4、PMA读写
在开始的时候就提到过PC和USB的交互是通过一段专属的数据缓冲区进行的,该数据缓冲区在硬件功能框图里面又被叫做Packet Buffer Memory,该区域在ST官方的USB库里面又被叫做Packet Memory Area,简称PMA.那么我们如何和这段内存进行交互呢?
首先从上面的信息里面可以知道,PMA的大小是512字节,可以通过APB1总线/USB控制器访问,且APB1的访问权限要高于USB.且软件部分通过Packet buffer interface访问(管理)PMA的存储空间,我们想使用的packet buffer的位置和大小可以随意配置,由buffer描述表指定。
buffer描述表,这个东西实在难理解,首先要明白,它本身也是占用内存的,且占用的内存也在PMA区域里面,但是这块内存的地址是由USB_BTABLE寄存器指定的!!!如下所示。

可以看到这个寄存器的功能只有一个,那就是保存了buffer描述表的起始地址。
通过上面的几段话,可以明白,想要操作这段内存空间(Packet Buffer Memory)就要对buffer描述表进行操作,但buffer描述表本身就处于这段内存中。那该如何操作这个描述表呢?这个描述表的大小又如何确定?
4.1、操作描述表
首先来看如何操作这个描述表,下面看官方提供的一段描述。

简单点说,这个描述表本身可以看成寄存器,使用操作寄存器的收发去操作。下面看一段官方的代码。
可以很清楚的看到,_wRegVal其实就是你要操作的ADDR_TX/RX的地址,这两段代码就是设置TX/RX缓冲区的起始地址。
这个时候已经设置好了数据存放的地址点了,但是数据交互的长度还没有设置,同理,如下所示。

其实也没什么好说的,就是根据数据量的不同,对寄存器进行设定,只是运算方法比较巧妙,有兴趣可以自己琢磨琢磨。
4.2、描述表大小的确定
上面说完了如何操作描述表,让我们可以自由的设定发送和接收的地址缓冲区和长度了,但如何确定你要使用的缓冲区地址呢,毕竟我要用的缓冲区和描述表是出于同一段内存空间的。下面看一张图。

有了上面的知识,应该已经知道能大概理解这张图的含义了,可以看出每个端点所使用的描述表大的大小为8个字节,简单点理解
描述表大小 = MAN_EP_NUM*8
结合例子,可以看到端点0的地址设定的是0X18(24),意思就是前24个字节用于缓冲区描述符,后续的各项间隔为0X40,其实就是端点描述符中的wMaxPacketSize.
其实我挺好奇的,复合设备的端点用的是0、1、2的双向端点,3的单向端点,其实按道理来说这地方应该是0X20,但是依旧能正常使用,后来经过实际测试,发现在通讯过程的并没有CDC_CMD_EP的传输数据。所以只使用了0,1,2三个端点。所以这个地方还是可以正常使用的。
建议使用端点的时候最好使用连续的端点,如果使用的是0,1,3.计算的时候还是需要按照4个端点进行计算的,端点2虽然没有使用,但是在实际的内存空间里面还是有端点2的描述表的。这样的话就会有空间浪费。
下面说一些我整了半天才整明白的概念,可能有点简单,但是我确实很迷。

简单说一下,USB_EPnR寄存器的低四位是专门存储端点地址的,比如我们在EP1R的寄存器里面写入0X0A,那么我们代码里面使用的EP1的实际地址就是0X0A,那么如果你的实际端点号其实是0X0A,但是在代码层面8个端点被抽象成为了IN_ep[8],调用的时候使用IN_ep[1]操作的依然是0X0A端点,实现了对底层的抽象。

还有就是一直说STM32有8个双向端点,可以作为16个单向端点使用,我被这句话迷惑了好久,明明只有8个EPnrR寄存器,为什么可以使用16个单向端点,后来在上述图片内看到这句话,才明白,USB_IP最多只能使用8个端点,也就是说,我们不能同时使用15个IN/OUT端点。
他说的这16个单向端点受EPnR控制,说的就是受上图红框内的寄存器位控制。
举报