目录
源码下载请参考链接:USB -- STM32-FS-USB-Device驱动代码简述(二)
USB -- STM32F103虚拟串口bulk传输讲解(三)
USB -- STM32F103自定义HID设备及HID上位机中断传输讲解(四)
USB -- STM32F103 U盘(MassStorage)SDIO接口SCSI协议Bulk传输讲解(五)
USB -- STM32F103 USB DFU设备固件升级(IAP)控制传输讲解(六)
USB -- STM32F103 USB AUDIO(音频)Speak同步传输(Out传输)讲解(七)
USB -- STM32F103 USB AUDIO(音频)Microphone同步传输(In传输)讲解(八)
USB -- STM32F103 USB VIDEO(视频)Camera同步传输讲解(九)
USB -- STM32F103复合设备(HID+MassStorage)传输讲解(十)
前面的章节带大家认识了Bulk传输和同步传输,STM32F103的USB为了提高Bulk和同步传输的传输效率,设计了一种双buffer的传输机制,下面就让博主为大家简单的讲解一下双缓冲端点的原理,如有错误,请大家指正。
引用STM32F103的中文手册对双缓冲端点的解释:
“USB标准不仅为不同的传输模式定义了不同的端点类型,而且对这些数据传输所需要的系统要求做了描述。其中,批量端点适用于在主机PC和USB设备之间传输大批量的数据,因为主机可以在一帧内利用尽可能多的带宽批量传输数据,使传输效率得到提高。然而,当USB设备处理前一次的数据传输时,又收到新的数据分组,它将回应NAK分组,使PC主机不断重发同样的数据分组,直到设备在可以处理数据时回应ACK分组。这样的重传占用了很多带宽,影响了批量传输的速率,因此引入了批量端点的双缓冲机制,提高数据传输率”。
当然这个解释不仅适用批量传输,同样也适用同步传输,只是同步传输没有ACK应答机制,最终的目的也是为了提高传输效率。
我们这里主要是以批量传输来讲解,同步传输类似。
下图是普通端点的传输示意图(OUT包),正常的流程是PC下发数据到Buffer,USB读取Buffer中的数据。
但是当PC发送的数据过多和过快的时候,USB模块还没来得及取完Buffer的数据的时候,就会给PC回复NAK指令,此时PC就一直下发相同数据,直到USB把Buffer中的数据读取完回复ACK。
下图是双Buffer原理示意图(OUT包),它类似一种乒乓的概念。也就是当USB模块读取其中一个Buffer的数据的时候,另一个空闲的Buffer能够及时接收PC下发的数据。这样就能提高USB的传输效率。
可以这样理解,普通传输就像串行传输一样,需要一步一步的传输(发完之后再接,接完之后再发);而双缓冲端点就像并行传输一样,使数据能够同时进行发送和接收(只是这里接收的数据是上一次发送的数据)。
以下是STM32F103中文手册对双缓冲端点使用的解释:
使用双缓冲机制时,单向端点的数据传输将使用到该端点的接收和发送两块数据缓冲区。数据翻转位用来选择当前使用到两块缓冲区中的哪一块,使应用程序可以在USB模块访问其中一块缓冲区的同时,对另一块缓冲区进行操作。例如,对一个双缓冲批量端点进行OUT分组传输时,USB模块将来自PC主机的数据保存到一个缓冲区,同时应用程序可以对另一个缓冲区中的数据进行处理(对于IN分组来说,情况是一样的)。
因为切换缓冲区的管理机制需要用到所有4个缓冲区描述表的表项,分别用来表示每个方向上的两个缓冲区的地址指针和缓冲区大小,因此用来实现双缓冲批量端点的USB_EpnR寄存器必需配置为单向。所以只需要设定STAT_RX位(作为双缓冲批量接收端点)或者STAT_TX位(作为双缓冲批量发送端点)。如果需要一个双向的双缓冲批量端点,则须使用两个USB_EpnR寄存器。
为尽可能利用双缓冲的优势,达到较高的传输速率,双缓冲批量端点的流量控制流程与其他端点的稍有不同。它只在缓冲区发生访问冲突时才会设置端点为NAK状态,而不是在每次传输成功后都将端点设为NAK状态。
DTOG位用来标识USB模块当前所使用的储存缓冲区。双缓冲批量端点接收方向的缓冲区由DTOG_RX(USB_EpnR寄存器的第14位)标识,而双缓冲批量端点发送方向的缓冲区由DTOG_TX(USB_EpnR寄存器的第6位)标识。同时,USB模块也需要知道当前哪个缓冲区正在被应用程序使用,以避免发生冲突。由于USB_EpnR寄存器中有2个DTOG位,而USB模块只使用其中的一位来标识硬件所使用的缓冲区,因此,应用程序可使用另一位来标识当前正在使用哪个缓冲区,这个新的标识被称为SW_BUF位。下表列出了双缓冲批量端点在实现发送和接收操作时,USB_EPNR寄存器的DTOG位和SW_BUF位之间的关系。
缓冲区标识位 | 作为发送端点 | 作为接收端点 |
DTOG | DTOG_TX(USB_EPxR寄存器的第6位) | DTOG_RX(USB_EPxR寄存器的第14位) |
SW_BUF | USB_EPxR寄存器的第14位 | USB_EPxR寄存器的第6位 |
USB模块当前使用的缓冲区由DTOG位标识,而应用程序所使用的缓冲区由SW_BUF位标识,这两个位的标识方式相同,下表描述了这种标识方式。
端点类型 | DTOG位 | SW_BUF位 | USB模块使用的缓冲区 | 应用程序使用的缓冲区 |
IN端点 | 0 | 1 | ADDRx_TX_0/COUNTx_TX_0 | ADDRx_TX_1/COUNTx_TX_1 |
1 | 0 | ADDRx_TX_1/COUNTx_TX_1 | ADDRx_TX_0/COUNTx_TX_0 | |
0 | 0 | 无(1) | ADDRx_TX_0/COUNTx_TX_0 | |
1 | 1 | 无(1) | ADDRx_TX_0/COUNTx_TX_0 | |
OUT端点 | 0 | 1 | ADDRx_RX_0/COUNTx_RX_0 | ADDRx_RX_1/COUNTx_RX_1 |
1 | 0 | ADDRx_RX_1/COUNTx_RX_1 | ADDRx_RX_0/COUNTx_RX_0 | |
0 | 0 | 无(1) | ADDRx_RX_0/COUNTx_RX_0 | |
1 | 1 | 无(1) | ADDRx_RX_0/COUNTx_RX_0 |
?(1)端点处于NAK状态。
如果是批量传输,使用双缓存端点需要使用下列方式设置: