一. 前言
DWC2支持S/G DMA即Scatter/Gather DMA模式,该DMA模式可以解放CPU实现高效的数据流。
当然需要IP配置支持该模式,寄存器GHWCFG4的bit32为1时表示当前IP配置支持该DMA模式。
IP支持该模式时,用户还可以配置是否使能该模式,
设备模式时软件配置DCFG寄存器的bit23为1表示使能该DMA模式,当然此时必须使能DMA模式即GAHBCFG寄存器的DMAEn配置为1。如果是HOST模式的话是配置HCFG的bit23.
二. S/G DMA的启动与停止
S/G DMA的设计初衷是使用描述符链表,用于硬件DMA和软件的交互,实现不间断的流式处理, 用户只需要准备描述符,高速硬件描述符准备好可以开始处理,剩下的就交给硬件S/G DMA去处理,硬件DMA不断扫描描述符来进行对应的数据搬运。搬运完则产生中断,停止或者不停止继续绕回到描述符链表开始继续处理。硬件和软件配合,可以实现ring环形不间断的流式处理。
这种方式天生就适合ISOC传输这种流式不间断的传输,所以对于ISOC,S/G DMA是不自动停止的(除非遇到错误或者描述符未就绪)。而对于BULK等非等时传输,则处理完一个描述符链表(L=1)则自动停止,当然还留了一手即可配置描述符的MTRF=1来表示需要流式处理,此时遇到L=1的描述符也不停止而是和ISOC一样继续处理。
简单的来说ISOC传输会不断循环处理描述符链表,而BULK和INT非等时传输则需要描述符MTRF=1来表示不断循环处理描述符链表,否则是遇到L=1则停止。
而S/G DMA的启动是通过DIEP和DOEP的控制寄存器的bit31的EPENA来设置的,软件设置该位为1来启动S/G DMA的处理,在此之前需要设置好描述符和DIEPDMAi/DOEPDMAi等信息。
硬件S/G DMA检查到EPENA为1时开始处理描述符,然后根据具体的停止条件(处理完或者遇到错误或者描述符未就绪)清除EPENA,当然软件也可以在已经设置EPENA未被硬件清零前主动设置EPENA为0来停止DMA工作。
以下是简单的总结
假设用户只准备一个描述符且设置了L=1,IOC=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 1
inep2 buf:281977ac tosnd 32 dma:28182f00 abff020 281977ac
inep2,int:281
inep2,xfer,ctrl:8480c0
inep2,bna,DMA=28182f08 8480c0
inep2 buf:281977ac tosnd 32 dma:28182f00 abff020 281977ac
inep2,int:281
inep2,xfer,ctrl:8480c0
inep2,bna,DMA=28182f08 8480c0
inep2 buf:281977ac tosnd 32 dma:28182f00 abff020 281977ac
inep2,int:281
inep2,xfer,ctrl:8480c0
inep2,bna,DMA=28182f08 8480c0
inep2 buf:281977ac tosnd 32 dma:28182f00 abff020 281977ac
inep2,int:201
inep2,xfer,ctrl:8480c0
inep2,bna,DMA=28182f08 8480c0
inep2 buf:281977ac tosnd 32 dma:28182f00 abff020 281977ac
mic set samp:16000
inep2,int:201
inep2,xfer,ctrl:8480c0
inep2,bna,DMA=28182f08 8480c0
inep2 buf:281977ac tosnd 32 dma:28182f00 abff020 281977ac
inep2,int:2291
inep2,xfer,ctrl:8480c0
inep2,bna,DMA=28182f08 8480c0
inep2 buf:281977ac tosnd 32 dma:28182f00 abff020 281977ac
inep2,int:2291
inep2,xfer,ctrl:8480c0
inep2,bna,DMA=28182f08 8480c0
inep2 buf:281977ac tosnd 32 dma:28182f00 abff020 281977ac
inep2,int:2291
inep2,xfer,ctrl:8480c0
inep2,bna,DMA=28182f08 8480c0
inep2 buf:281977ac tosnd 32 dma:28182f00 abff020 281977ac
inep2,int:2291
inep2,xfer,ctrl:8480c0
inep2,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
这里看到控制寄存器都是打印8480c0即EPENA=0,
理论上应该是产生complete中断时还未停止DMA此时EPENA=1,产生BNA中断时,DMA才停止,才会EPENA=0,只是BNA和complete中断同时产生了,所以这里看到的都是EPENA=0.
ISOC OUT
在准备接收时打印
在out中断中打印
打印信息如下
set itf 3 1
outep2 buf:28197914 torcv 32 dma:28182f78 e000020 28197914
sp set samp:32000
outep2,int:1
outep2,xfer,ctrl:800480c0
outep2,int:200
outep2,bna,DMA=28182f80 480c0
outep2 buf:28197914 torcv 64 dma:28182f78 e000040 28197914
outep2,int:2001
outep2,xfer,ctrl:800480c0
outep2,int:200
outep2,bna,DMA=28182f80 480c0
outep2 buf:28197914 torcv 64 dma:28182f78 e000040 28197914
先打印准备发送
outep2 buf:28197914 torcv 32 dma:28182f78 e000020 28197914
然后再打印,进入中断
outep2,int:1
再打印是complete中断,此时看到控制寄存器为800480c0,EPENA=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 28307040
outep2,int:1
outep2,xfer,ctrl:b8200
outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040
outep2,int:1
outep2,xfer,ctrl:a8200
outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040
outep2,int:1
outep2,xfer,ctrl:b8200
outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040
outep2,int:1
outep2,xfer,ctrl:a8200
outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040
outep2,int:1
outep2,xfer,ctrl:b8200
outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040
outep2,int:1
outep2,xfer,ctrl:a8200
outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040
outep2,int:1
outep2,xfer,ctrl:b8200
outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040
outep2,int:1
outep2,xfer,ctrl:a8200
outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040
outep2,int:1
outep2,xfer,ctrl:b8200
outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040
outep2,int:1
outep2,xfer,ctrl:a8200
outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040
outep2,int:1
outep2,xfer,ctrl:b8200
outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040
outep2,int:1
outep2,xfer,ctrl:a8200
outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040
outep2,int:1
outep2,xfer,ctrl:b8200
outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040
outep2,int:1
outep2,xfer,ctrl:a8200
outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040
outep2,int:1
outep2,xfer,ctrl:b8200
outep2 buf:28307040 torcv 1536 dma:28307c40 a000600 28307040
outep2,int:1
outep2,xfer,ctrl:a8200
outep2 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 2830600c
inep2,int:2091
inep2,xfer,ctrl:898200
inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600c
inep2,int:2091
inep2,xfer,ctrl:888200
inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600c
inep2,int:2091
inep2,xfer,ctrl:888200
inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600c
inep2,int:2091
inep2,xfer,ctrl:888200
inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600c
inep2,int:2091
inep2,xfer,ctrl:898200
inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600c
inep2,int:2091
inep2,xfer,ctrl:898200
inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600c
inep2,int:2091
inep2,xfer,ctrl:898200
inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600c
inep2,int:2091
inep2,xfer,ctrl:898200
inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600c
inep2,int:2091
inep2,xfer,ctrl:888200
inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600c
inep2,int:2091
inep2,xfer,ctrl:898200
inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600c
inep2,int:2091
inep2,xfer,ctrl:888200
inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600c
inep2,int:2091
inep2,xfer,ctrl:898200
inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600c
inep2,int:2091
inep2,xfer,ctrl:888200
inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600c
inep2,int:2091
inep2,xfer,ctrl:898200
inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600c
inep2,int:2091
inep2,xfer,ctrl:898200
inep2 buf:2830600c tosnd 5 dma:28307030 a000005 2830600c
inep2,int:2091
inep2,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 1
inep2 buf:281977fc tosnd 64 dma:28182f38
inep2,int
inep2,xfer,ctrl:848180
inep2,bna,DMA=28182f40 848180
inep2 done
inep2 buf:281977fc tosnd 64 dma:28182f38
inep2,int
inep2,bna,DMA=28182f40 848180
inep2 done
inep2 buf:281977fc tosnd 64 dma:28182f38
inep2,int
inep2,xfer,ctrl:848180
inep2,bna,DMA=28182f40 848180
inep2 done
inep2 buf:281977fc tosnd 64 dma:28182f38
inep2,int
inep2,xfer,ctrl:848180
inep2,bna,DMA=28182f40 848180
inep2 done
inep2 buf:281977fc tosnd 64 dma:28182f38
inep2,int
inep2,xfer,ctrl:848180
inep2,bna,DMA=28182f40 848180
inep2 done
inep2 buf:281977fc tosnd 64 dma:28182f38
inep2,int
inep2,xfer,ctrl:848180
inep2,bna,DMA=28182f40 848180
inep2 done
inep2 buf:281977fc tosnd 64 dma:28182f38
总共发送了7笔,第二笔没有产生XFERCOMPL中断。
第7笔不再产生XFERCOMPL和BNA中断。
此时也没有抓到总线上有数据。
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 OUT和IOSC IN的BNA时机不一样
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 1
outep2 buf:28197914 torcv 32 dma:28182f78 e000020 28197914
sp set samp:32000
outep2,int:1
outep2,xfer,ctrl:800480c0
outep2 buf:28197914 torcv 64 dma:28182f78 e000040 28197914
outep2,int:1
outep2,xfer,ctrl:800480c0
outep2 buf:28197914 torcv 64 dma:28182f78 e000040 28197914
outep2,int:1
outep2,xfer,ctrl:800480c0
outep2 buf:28197914 torcv 64 dma:28182f78 e000040 28197914
outep2,int:211
outep2,xfer,ctrl:800480c0
outep2,bna,DMA=28182f80 800480c0
outep2 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 IN和OUT的BNA产生的时机会有差异,详见文中解释。
中断中清除中断的时机,DMA[0]设置的位置也是需要注意的地方。
以上主要是明确了S/G DMA的启停与一些需要注意的地方,实际如何利用S/G DMA去实现高效无间断的流式传输是一个很重要的内容,后面有时间再分享。