基于DWC2的USB驱动开发-S/G DMA方式的启动与停止-EPENA状态BNA与XFER COMPLETE中断

文摘   2024-08-03 08:00   湖南  

一. 前言

DWC2支持S/G DMAScatter/Gather DMA模式,DMA模式可以解放CPU实现高效的数据流。

当然需要IP配置支持该模式,寄存器GHWCFG4bit321时表示当前IP配置支持该DMA模式。

IP支持该模式时,用户还可以配置是否使能该模式,

设备模式时软件配置DCFG寄存器的bit231表示使能该DMA模式,当然此时必须使能DMA模式即GAHBCFG寄存器的DMAEn配置为1。如果是HOST模式的话是配置HCFGbit23.

二. S/G DMA的启动与停止

S/G DMA的设计初衷是使用描述符链表,用于硬件DMA和软件的交互,实现不间断的流式处理, 用户只需要准备描述符,高速硬件描述符准备好可以开始处理,剩下的就交给硬件S/G DMA去处理,硬件DMA不断扫描描述符来进行对应的数据搬运。搬运完则产生中断,停止或者不停止继续绕回到描述符链表开始继续处理。硬件和软件配合,可以实现ring环形不间断的流式处理。

这种方式天生就适合ISOC传输这种流式不间断的传输,所以对于ISOCS/G DMA是不自动停止的(除非遇到错误或者描述符未就绪)。而对于BULK等非等时传输,则处理完一个描述符链表(L=1)则自动停止,当然还留了一手即可配置描述符的MTRF=1来表示需要流式处理,此时遇到L=1的描述符也不停止而是和ISOC一样继续处理。

简单的来说ISOC传输会不断循环处理描述符链表,而BULKINT非等时传输则需要描述符MTRF=1来表示不断循环处理描述符链表,否则是遇到L=1则停止。

S/G DMA的启动是通过DIEPDOEP的控制寄存器的bit31EPENA来设置的,软件设置该位为1来启动S/G DMA的处理,在此之前需要设置好描述符和DIEPDMAi/DOEPDMAi等信息。

硬件S/G DMA检查到EPENA1时开始处理描述符,然后根据具体的停止条件(处理完或者遇到错误或者描述符未就绪)清除EPENA,当然软件也可以在已经设置EPENA未被硬件清零前主动设置EPENA0来停止DMA工作。

以下是简单的总结

假设用户只准备一个描述符且设置了L=1IOC=1,硬件处理完这个描述符后是否主动停止DMA,是否产生BNA(描述符未就绪)中断。

如果完成当前描述符主动停止则只会产生XFER COMPLETE中断不会产生BNA中断,

如果不主动停止,继续绕回查询描述符,则由于描述符未就绪产生BNA,此时再被迫停止DMA



XFER COMPLETE中断

BNA中断


MTRF=0

INT/BULK OUT

产生

不产生

INT中断传输和BULK传输完全一样

INT/BULK IN

产生

不产生

ISOC IN

产生

产生

ISOC不管是IN还是OUT,不自动停,产生BNA才停。

BULK不管是IN还是OUT,会自动停,不产生BNA

ISOC OUT

产生

产生

MTRF=1

INT/BULK OUT

产生

产生

遇到L=1绕回到开始描述符继续处理 一旦设置所有描述符都要设置

INT/BULK IN

/

/

无该配置

ISOC IN

/

/

ISOC和控制传输无该配置

ISOC OUT

/

/

ISOC和控制传输无该配置

具体可以参考编程指导中的流程图

INT/BULK IN 如下图所示,

启动是EPENA置位,停止是遇到L=1的描述符,当然描述符未就绪产生BNA或者其他错误也会停止。所以是遇到L=1会主动停止。

INT/BULK OUT 如下图所示

启动是EPENA置位且RXFIFO中有数据,停止是遇到L=1的描述符,当然描述符未就绪产生BNA或者其他错误也会停止。所以是遇到L=1会主动停止。

下图所示应该停止条件应该是错误的,应该画成了ISOC OUT的图,BULK OUT

MTRF=0时遇到L=1是会主动停止的,MTRF=1时才会继续绕回到开头的描述符继续处理。

ISOC IN

启动是EPENA置位,遇到L=1不主动停止而是绕回到开始描述符继续处理,当然描述符未就绪产生BNA或者其他错误也会停止。

ISOC OUT

启动是EPENA置位且RXFIFO有数据,遇到L=1不主动停止而是绕回到开始描述符继续处理,当然描述符未就绪产生BNA或者其他错误也会停止。

.实测

以下对MTRF=0的各种情况进行测试

ISOC IN

In中断中打印如下信息

准备发送时打印以下信息

可以看到打印信息如下

set itf 4 1inep2 buf:281977ac tosnd 32 dma:28182f00 abff020 281977acinep2,int:281inep2,xfer,ctrl:8480c0inep2,bna,DMA=28182f08 8480c0inep2 buf:281977ac tosnd 32 dma:28182f00 abff020 281977acinep2,int:281inep2,xfer,ctrl:8480c0inep2,bna,DMA=28182f08 8480c0inep2 buf:281977ac tosnd 32 dma:28182f00 abff020 281977acinep2,int:281inep2,xfer,ctrl:8480c0inep2,bna,DMA=28182f08 8480c0inep2 buf:281977ac tosnd 32 dma:28182f00 abff020 281977acinep2,int:201inep2,xfer,ctrl:8480c0inep2,bna,DMA=28182f08 8480c0inep2 buf:281977ac tosnd 32 dma:28182f00 abff020 281977acmic set samp:16000inep2,int:201inep2,xfer,ctrl:8480c0inep2,bna,DMA=28182f08 8480c0inep2 buf:281977ac tosnd 32 dma:28182f00 abff020 281977acinep2,int:2291inep2,xfer,ctrl:8480c0inep2,bna,DMA=28182f08 8480c0inep2 buf:281977ac tosnd 32 dma:28182f00 abff020 281977acinep2,int:2291inep2,xfer,ctrl:8480c0inep2,bna,DMA=28182f08 8480c0inep2 buf:281977ac tosnd 32 dma:28182f00 abff020 281977acinep2,int:2291inep2,xfer,ctrl:8480c0inep2,bna,DMA=28182f08 8480c0inep2 buf:281977ac tosnd 32 dma:28182f00 abff020 281977acinep2,int:2291inep2,xfer,ctrl:8480c0inep2,bna,DMA=28182f08 8480c0

即先打印准备接收

inep2 buf:281977ac tosnd 32 dma:28182f00 abff020 281977ac

再打印进入中断

inep2,int:201

再打印同时进了complete中断

inep2,xfer,ctrl:8480c0

BNA中断

inep2,bna,DMA=28182f08 8480c0

这里看到控制寄存器都是打印8480c0EPENA=0

理论上应该是产生complete中断时还未停止DMA此时EPENA=1,产生BNA中断时,DMA才停止,才会EPENA=0,只是BNAcomplete中断同时产生了,所以这里看到的都是EPENA=0.

ISOC OUT

在准备接收时打印

out中断中打印

打印信息如下

set itf 3 1outep2 buf:28197914 torcv 32 dma:28182f78 e000020 28197914sp set samp:32000outep2,int:1outep2,xfer,ctrl:800480c0outep2,int:200outep2,bna,DMA=28182f80 480c0outep2 buf:28197914 torcv 64 dma:28182f78 e000040 28197914
outep2,int:2001outep2,xfer,ctrl:800480c0outep2,int:200outep2,bna,DMA=28182f80 480c0outep2 buf:28197914 torcv 64 dma:28182f78 e000040 28197914

先打印准备发送

outep2 buf:28197914 torcv 32 dma:28182f78 e000020 28197914

然后再打印,进入中断

outep2,int:1

再打印是complete中断,此时看到控制寄存器为800480c0EPENA=1,即DMA没有停止。

后面主机在此OUT数据过来,此时由于软件没准备描述符,所以产生BNA中断

打印

outep2,int:200

outep2,bna,DMA=28182f80 480c0

即有xfer complete中断,BNA中断。

当前笔OUT能正常接收只缠上complete中断,过了一会主机继续OUT,此时没有准备描述符才会产生BNA,此时才停止DMA

BULK OUT

在准备接收时打印

out中断中打印

打印信息如下

outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040outep2,int:1outep2,xfer,ctrl:b8200outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040outep2,int:1outep2,xfer,ctrl:a8200outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040outep2,int:1outep2,xfer,ctrl:b8200outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040outep2,int:1outep2,xfer,ctrl:a8200outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040outep2,int:1outep2,xfer,ctrl:b8200outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040outep2,int:1outep2,xfer,ctrl:a8200outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040outep2,int:1outep2,xfer,ctrl:b8200outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040outep2,int:1outep2,xfer,ctrl:a8200outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040outep2,int:1outep2,xfer,ctrl:b8200outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040outep2,int:1outep2,xfer,ctrl:a8200outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040outep2,int:1outep2,xfer,ctrl:b8200outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040outep2,int:1outep2,xfer,ctrl:a8200outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040outep2,int:1outep2,xfer,ctrl:b8200outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040outep2,int:1outep2,xfer,ctrl:a8200outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040outep2,int:1outep2,xfer,ctrl:b8200outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040outep2,int:1outep2,xfer,ctrl:a8200outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040

可以看到先打印

outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040

再打印中断

outep2,int:1

再打印xfer complete中断,此时控制寄存器为a8200,即DMA停止EPENA=0.

outep2,xfer,ctrl:b8200

即只有xfer complete中断,没有BNA中断,因为DMA自动停止了。

BULK IN

In中断中打印如下信息

准备发送时打印以下信息

打印信息如下

inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600cinep2,int:2091inep2,xfer,ctrl:898200inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600cinep2,int:2091inep2,xfer,ctrl:888200inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600cinep2,int:2091inep2,xfer,ctrl:888200inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600cinep2,int:2091inep2,xfer,ctrl:888200inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600cinep2,int:2091inep2,xfer,ctrl:898200inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600cinep2,int:2091inep2,xfer,ctrl:898200inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600cinep2,int:2091inep2,xfer,ctrl:898200inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600cinep2,int:2091inep2,xfer,ctrl:898200inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600cinep2,int:2091inep2,xfer,ctrl:888200inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600cinep2,int:2091inep2,xfer,ctrl:898200inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600cinep2,int:2091inep2,xfer,ctrl:888200inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600cinep2,int:2091inep2,xfer,ctrl:898200inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600cinep2,int:2091inep2,xfer,ctrl:888200inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600cinep2,int:2091inep2,xfer,ctrl:898200inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600cinep2,int:2091inep2,xfer,ctrl:898200inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600cinep2,int:2091inep2,xfer,ctrl:898200

先打印准备发送

inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600c

然后打印进入中断

inep2,int:2091

再打印xfer complete中断

inep2,xfer,ctrl:898200

即只有xfer complete中断,没有BNA中断,因为DMA自动停止了。

.需要注意的地方

4.1 清除中断时机问题

清除中断要读取中断之后马上清除,因为中断服务函数处理时可能又会有新的中断,如果在中断函数靠后清除,就会清除新产生的中断。

set itf 4 1inep2 buf:281977fc tosnd 64 dma:28182f38inep2,intinep2,xfer,ctrl:848180inep2,bna,DMA=28182f40 848180inep2 doneinep2 buf:281977fc tosnd 64 dma:28182f38inep2,intinep2,bna,DMA=28182f40 848180inep2 doneinep2 buf:281977fc tosnd 64 dma:28182f38inep2,intinep2,xfer,ctrl:848180inep2,bna,DMA=28182f40 848180inep2 doneinep2 buf:281977fc tosnd 64 dma:28182f38inep2,intinep2,xfer,ctrl:848180inep2,bna,DMA=28182f40 848180inep2 doneinep2 buf:281977fc tosnd 64 dma:28182f38inep2,intinep2,xfer,ctrl:848180inep2,bna,DMA=28182f40 848180inep2 doneinep2 buf:281977fc tosnd 64 dma:28182f38inep2,intinep2,xfer,ctrl:848180inep2,bna,DMA=28182f40 848180inep2 doneinep2 buf:281977fc tosnd 64 dma:28182f38

总共发送了7笔,第二笔没有产生XFERCOMPL中断。

7笔不再产生XFERCOMPLBNA中断。

此时也没有抓到总线上有数据。

set itf 4 1

inep2 buf:281977fc tosnd 64 dma:28182f38 abff040 281977fc

inep2,int

inep2,xfer,ctrl:848180

inep2,bna,DMA=28182f40 848180

inep2 done

inep2 buf:281977fc tosnd 64 dma:28182f38 abff040 281977fc

此时的寄存器值0x03000940开始

00848180 00000000 00000080 00000000 0007ff80 28182f40 00000040 2819783c 00000000 00000000 00000080 00000000


改为

4.2 ISOC OUTIOSC INBNA时机不一样

ISOC的IN和OUT产生BNA的时机不一样

对于IN,上一笔描述符处理完,只要TXFIFO还有空间,就会马上处理下一笔描述符,如果此时没有准备好下一笔描述符,就会马上产生BNA,所以complete和bna是同时产生。 

而对于OUT上一笔描述符处理完,DMA需要收到数据到RXFIFO,才会去处理下一个描述符如果下一个描述符不就绪,才会产生BNA,所以complete之后,要等下一笔数据来才会产生BNA

4.3 DMA设置的位置

DMA[0]要最后设置,因为如果DMA没有停止时,软件去更新描述符,硬件是需要读取到DMA[0]的状态是允许DMA访问才会去访问,所以软件要把所有信息准备好,才最后配置DMA[0]的这部分信息,这样保证硬件可以访问描述符时,其他信息都是就绪的。

set itf 3 1outep2 buf:28197914 torcv 32 dma:28182f78 e000020 28197914sp set samp:32000outep2,int:1outep2,xfer,ctrl:800480c0outep2 buf:28197914 torcv 64 dma:28182f78 e000040 28197914outep2,int:1outep2,xfer,ctrl:800480c0outep2 buf:28197914 torcv 64 dma:28182f78 e000040 28197914outep2,int:1outep2,xfer,ctrl:800480c0outep2 buf:28197914 torcv 64 dma:28182f78 e000040 28197914outep2,int:211outep2,xfer,ctrl:800480c0outep2,bna,DMA=28182f80 800480c0outep2 buf:28197914 torcv 64 dma:28182f78 e000040 28197914

Int:211说明,已经BNA导致DMA停止了,即EPENA=0了,新的OUT来了,此时EPENA=0所以产生OUTTknEPdis事件。

五. 总结

使用S/G DMA模式时需要注意DMA的启停条件,ISOC硬件不会主动停止所以如果未及时准备下一个描述符就会导致BNA中断需要合适的处理,非ISOC硬件遇到L=1描述符会自动停止,所以软件可以足够的时间准备下一个描述符再重新启动。

对于ISOC INOUTBNA产生的时机会有差异,详见文中解释。

中断中清除中断的时机,DMA[0]设置的位置也是需要注意的地方。

以上主要是明确了S/G DMA的启停与一些需要注意的地方,实际如何利用S/G DMA去实现高效无间断的流式传输是一个很重要的内容,后面有时间再分享。



嵌入式Lee
嵌入式软硬件技术:RTOS,GUI,FS,协议栈,ARM,总线,嵌入式C,开发环境 and blablaba....多年经验分享,非硬货不发,带你扒开每一个技术背后的根本原理。
 最新文章