基于DWC2的USB驱动开发-发送相关的寄存器DMA寄存器详解

描述

本文转自公众号,欢迎关注

基于DWC2的USB驱动开发-发送相关的寄存器DMA寄存器详解 (qq.com)

前言

如下寄存器DIEPxxx,对应IN端点,和发送数据相关,这一篇先介绍和DMA相关的两个寄存器,其他的后续再讲,

并且通过观察其寄存器的实际值的变化来加深理解。

了解这些值的含义以及何时如何变化,可以在有问题时帮助进行调试,知道当前出于何种状态。

以下实例是以Scatter/Gather DMA模式IN端点1进行操作

寄存器的地址偏移分别是

0x900+i*0x20

0x908+i*0x20

0x910+i*0x20

0x914+i*0x20

0x918+i*0x20

0x91C+i*0x20

dma

DIEPDMA****i

寄存器偏移:0x914 + i*20

Scatter/Gather DMA模式时该寄存器的值即用户指定的描述符链表的地址

非Scatter/Gather DMA时该寄存器的值即用户指定的DMA待发送数据的地址。

必须DWORD即8字节对齐。

比如这里描述符链表使用了全局数组,用attribute指定对齐大小

attribute ((aligned(8))) static uint32_t s_dam[1024][2];

注意该寄存器在每次处理完描述符后会递增,用户可以通过该寄存器判断DMA是否进行了描述符的处理。

注意该寄存器需要CTL寄存器ENA置位后才能回读否则读到的是0.

我们以一个实例来看该寄存器值的变化,以下是关键代码,即准备一次DMA发送,前面描述符的准备过程不在这里贴出。

void ep_writedma(uint32_t dma, uint8_t epnum)
{
  REG_DIEP_DMA(epnum) = dma;
  REG_DIEP_CTL(epnum) |= (DEP_ENA_BIT | DEP_CLEAR_NAK);
}

以下是执行REG_DIEP_DMA(epnum) = dma;前,寄存器DIEPDMA1的值为0

传入的参数即描述符链表的地址是0x81008d8是8字节的对齐的

此时a0为0x81008d8,即我们的描述符链表的地址

a4为寄存器地址0x3000934,sw a0,0(a4) 即将0x81008d8写入寄存器0x3000934
dma

注意在CTL寄存器使能端点之前是不能回读该寄存器的值的,如下为0

执行完sw语句再来看,此时DIEPDMA1还是0

dma

在执行完使能,CTL寄存器的ENA置位后才能看到,如下此时看待DIEPDMA1的值变为了0x08100968,为什么不是写入的0x81008d8呢,也就时之前说的,ENA一置位,DMA就会去处理该描述符,0x08100968-0x81008d8=0x90=144 ,144/8=18个描述符(一个描述符2个WORD8字节)。

dma

那么为什么该寄存器值递增了这么多呢

那是因为我们这里配置p_dam就是配置了18个描述符,如下18个DWORD,所以可以看到如下18个描述符一起处理完了,最后一个描述符标志了是最后一个。

dma

DIEPDMABi

寄存器偏移:0x91C + i*20

该寄存器只有Scatter/Gather DMA模式有效,非Scatter/Gather DMA模式,DIEPDMAi就是用户缓冲区的地址,也就是Scatter/Gather DMA模式的本寄存器。

用于指示当前正在处理的用户缓冲区的地址,DMA处理完指定缓冲区后就会更新。

所以从该寄存器可以看到是否处理了用户的缓冲区数据。

同样是CTL的ENA置位后,处理完描述符后更新,从以下可以看出最后一个描述的用户数据缓冲区地址为0x8704400长度为0x3C1,所以处理完后DIEPDMAB1更新为了0x87047C1

dma

总结

这里重点讲解了DMA相关的两个寄存器,主要是他们可以协助分析数据发送,比如有时候数据没有发出,可以从这里看出是否处理了描述符,是否处理了用户数据,来协助判断当前状态。

审核编辑 黄宇

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分