This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

关于mcbsp模块打开FIFO功能收不到EDMA中断的情况

一直在omapl138平台上面使用mcbsp的TX和RX进行数据的收发,采用EDMA的pingpong模式,BFIFO功能都是关闭着的,随着EDMA_CC0通道使用多了, 需要打开MCBSP的FIFO功能,根据文档上面解释,只要在mcbsp跳出reset模式之前打开都可以,所以在mcbsp初始化的时候,讲mcbsp进入reset模式之后,添加配置BFIFO,enable BFIFO,讲串行位宽配置为1 word,缓存大小配置为32bits的整数倍,每种倍数都尝试过,只要打开BFIFO功能,EDMA就进不了中断了,之前默认没有使用BFIFO功能的时候mcbsp都可以正常工作;

网上没有找到关于打开BFIFO功能的mcbsp例程,TI的例子里面也是没有提到BFIFO这个功能,请tony哥帮我看看,出谋划策一下,其他有遇到此类问题的同行们请赐教一下。

多谢!

  • 用FIFO后,EDMA的参数要根据FIFO的配置来设置,即EDMA的A Count要设为FIFO的深度。当FIFO空出来所设置的FIFO阀值时,则产生EDMA Event,这时EDMA必需将FIFO阀值所需的数据一次性送给FIFO。

    如果还有问题,则将配置贴上来看一下。

  • tony哥,打开FIFO的操作在配置MCBSP之前就调用了,深度为40words,每个words长度为32bits,对应的edma的配置如图,以前没有用FIFO的时候首地址为MCBSP_DRR,现在改为FIFO_DATA,A count值以前是4字节,就是DRR的宽度,现在改为4*40=FIFO的长度,对应的把B count缩短为原来的1/40,这样子写进不了EDMA的中断,帮我看看哪里有问题?

    昨天调用使能FIFO的库函数接口,将FIFO深度设置为64words,源地址FIFO_DATA,a count = 4的时候都可以正常工作的。

  • tony:

    怎么保证EDMA将FIFO阀值所需的数据一次性送给FIFO?通过把a count的值跟FIFO的阈值配置一致还是有其他办法?

     

  • bingliang chen 说:
    怎么保证EDMA将FIFO阀值所需的数据一次性送给FIFO?通过把a count的值跟FIFO的阈值配置一致还是有其他办法?

    对。如果是A-sync,那么一个event则要所需数据都送给FIFO,否则FIFO不给新的event了,因为FIFO会认为送出去的事件还没有被服务完。

  • bingliang chen 说:
    A count值以前是4字节,就是DRR的宽度,现在改为4*40=FIFO的长度,对应的把B count缩短为原来的1/40,

    现在用的是A-sync还是AB-sync?

  • 刚才把配置打印出来,确认是采用A-sync,但是每次传送数据是640个words,所以虽然A-count改为4*40bytes了,但是B-count值不能为1,需要是16,这种配置我理解为就是每次传送4*40bytes时TC会给CC发送event,然后B-count的值减为0的时候EDMA控制器收到一起传送结束的标志,应用程序可以填新数据到传送完的640个words区域。

    这里有一点不明白c-count值干嘛用的?

  • tony:

    已经确认了是A-sync,但是只能进一次EDMA中断,ping-pong跑不起来了。

    因为出现了mcbsp发不出来的问题,加上fifo为了event queue可以少点压力,不加FIFO的话,每4bytes就会产生一个FIFO,现在加了FIFO的话,应该是FIFO传输完再产生一个event,现在配置为a-count=fifo大小,b-count = (ping或者pong的长度/a-count),c-count = 1;

    由于保密关系,代码拷贝不出来,之前不用FIFO的时候a-count=4, b-count = 640, c-count = 1, A-sync配置,这样是可以正常跑的,加上FIFO之后就是把目的地址从mcbsp的shift register改为FIFO_data,然后a-count=fifo大小,b-count = 640/FIFO深度,跑不起来了,还有哪里没有配置好嘛?

  • tony,我已经把代码改为可读性强一些的宏定义了,在mcbsp初始化之前把FIFO打开了,而且配置深度是32,DMA配置中目标地址也改为了FIFO_DATA地址,当BFIFO_DEEPTH=1时可以正常跑起来,而改为BFIFO_DEEPTH=20或者BFIFO_DEEPTH=32都没法正常跑,是不是哪里还没有配置好?

    可以确定肯定是A-sync,因为opt寄存器的bit2位已经反复确认了,而且不用FIFO时能跑起来也证明了是A-sync。

  • tony哥:

          以下是完整的一个DMA PAR配置的代码,跟不用FIFO的区别就是a-count   b-count  bCntReload这三个地方要根据不同的FIFO深度进行修改,帮我看一下还要改哪里?

  • bingliang chen 说:

    我已经把代码改为可读性强一些的宏定义了,在mcbsp初始化之前把FIFO打开了,而且配置深度是32,DMA配置中目标地址也改为了FIFO_DATA地址,当BFIFO_DEEPTH=1时可以正常跑起来,而改为BFIFO_DEEPTH=20或者BFIFO_DEEPTH=32都没法正常跑,是不是哪里还没有配置好?

    可以确定肯定是A-sync,因为opt寄存器的bit2位已经反复确认了,而且不用FIFO时能跑起来也证明了是A-sync。

    怎么上面还是 srcBIdx=short 4;  aCnt都是4*BFIFO_DEEPTH了。

  • bingliang chen 说:
    刚才把配置打印出来,确认是采用A-sync,但是每次传送数据是640个words,所以虽然A-count改为4*40bytes了,但是B-count值不�为1,需要是16,这种配置我理解为就是每次传送4*40bytes时TC会给CC发送event,然后B-count的值减为0的时候EDMA控制器收到一起传送结束的标志,应用程序可以填新数据到传送完的640个words区域。

    差不多这个意思吧,但是不知道什么是:应用程序可以填新数据到传送完的640个words区域

    bingliang chen 说:
    这里有一点不明白c-count值干嘛用的?

    减完B减C,C也减到0时,这个paraset才真正用完,参数 EDMA complete interrupt

  • tony哥:

    你的意思是我的opt里面的srcBIdx值应该配置成跟aCnt的值一致?

  • tony哥:

    把srcBIdx的值改为= aCnt=4*BFIFO_DEEPTH,还是跑不起来,是不是edma的某个地方还要做对应的修改?所有的pingpong配置代码都是调用贴上来的这个函数的。

  • 你的宏定义BFIFO_DEEPTH, MCBSP_RX_LEN, 还有一个pingparamSet.bCnt = (unsigned short) len/BFIFO_DEEPTH;里的len到底是多少啊?

    感觉这里的参数差了一个4倍关系。

    如果说BFIFO_DEEPTH = 32,  则aCnt=128byte, MCBSP_RX_LEN是640,还是640/4?

    如果接收的数据是连续放的话,RX的destBIdx肯定要是4*BFIFO_DEEPTH。

    TX同理。

  • MCBSP_RX_LEN和MCBSP_TX_LEN都是640,但是单位是4字节,用的是640的整型数组。所以a_count 128字节,b_count 20 c_conut 1 ,相当于一个传输完成是2560个字节。但是TC产生一个event 应该是a_count 128个字节,跟BFIFO大小一样。
  • 那这个bCnt就没问题了。

    如果都按我前面说的改过来了,那么现在的现象是什么?还是ping能work?不能到pong?还是只传输了部分?

  • 按照昨晚发的最后的配置配下去,进一次完成中断就没有了,感觉是PINGPONG跑不起来,就跑了一次。
  • 按今天的,把bIdx也改正确后的结果?

    检查paramset是否link过去了?

  • 现在就是后面有srcBIdx destBIdx怎么配不知道?手册里面只写如果用a-sync的话srcCIdx和destCIdx都该配为0,以前不用BFIFO的时候DAM和SAM都是配置为INCR,现在用上了BFIFO,是不是发送端要把目标地址模式改为CONST,接收端要把源地址模式改为CONST模式?
  • 还有这个bCntReload值该填什么?以前不用BFIFO的时候填0也可以工作的,现在是不是要填bCnt的值?
  • 怎么就不知道怎么配srcBIdx destBIdx,前面我已经截图了,如果是发送,srcBIdx则是aCnt,如果是接收,destBIdx则是aCnt,FIFO的地址只有一个,与它相关的Idx都是0。

    DAM和SAM永远都是自增模式。

    现在用了FIFO与你以前的只有两个区别。

    #1. 地址变了。

    #2. 一次Event传输的数据长度变了,以前是一个word,因为只有一个数据寄存器,一次只能收发一个word。现在用了FIFO,则一次传输FIFO配置的深度。

  • 好的,按照你的思路重新梳理一遍,再不行的话把发送和接收的配置都贴上来
  • bingliang chen 说:
    还有这个bCntReload值该填什么?以前不用BFIFO的时候填0也可以工作的,现在是不是要填bCnt的值?

    Ccnt=1, 所以这个Reload配不配关系不大。可以配置为Bcnt.

  • Tony哥:

    现在把打开FIFO的配置和MCBSPTX MCBSPRX的EDMA配置依次贴出来,请您帮我看一下,BFIFO_DEEPTH = 32,BFIFO的深度也是32,依次改变的地方就是:1.目标地址改为MCBSP_FIFO_DATA寄存器地址;2.发送时aCnt = 4*BFIFO_DEEPTH, bCnt = len/BFIFO_DEEPTH,srcBIdx = aCnt;3.接收时aCnt = 4*BFIFO_DEEPTH, bCnt = len/BFIFO_DEEPTH,destBIdx = aCnt。

    按照上面说的配置把宏BFIFO_DEEPTH改为32就跑不起,改为1就可以正常跑,改为2就跑一两秒就没有了。

     

  • 设成32跑不起来,你也可以看看paraset里的 Bcnt, 地址等有没有变化。

    以及FIFO寄存器的状态显示FIFO里还有多少个数?

    1能跑起来,说明EDMA配置没有问题了。2能跑2秒,也可以说明EDMA配置没啥问题,毕竟2秒对硬件来说时间不短了。32不行,是不是McBSP没在动作了?

  • tony哥: 我先看看mcbsp这边
  • tony: 昨天半夜时我看到一个文档说用BFIFO的话,放数据的内存地址必须256位对齐,不知道这个要求对不对?
  • tony哥:

    刚才我用示波器确认了一下,为什么BFIFO设置为2的深度可以跑2秒钟,BFIFO设置为1时可以完全跑起来,设置为4或者比4大的话完全跑跑不起来,发现设置为1的时候中断来的时间跟设计是一致的,4ms产生一个中断;但是设置BFIFO深度为2的时候发现中断时间变成了2ms;

    但是MCBSP的帧同步和位同步时钟都采用从模式的,帧同步一直是160K,为什么BFIFO的改变会让速率提高了一倍呢?以下是在中断里面拉电平的记录:

  • 为什么在设为1时,不是1/160Hz=6.25ms,而4ms是对的?

    我怎么觉得上面的间隔是搞反了,不可能FIFO加深中断间隔反而提高了。

  • tony哥:

    因为帧同步信号160K是外部给MCBSP的,这个示波器测量过了,不管是2ms还是4ms帧同步信号都是160Khz,设计思路是640个数据发送完产生一个中断,640/160=4,所以当BFIFO深度设置为1的时候,4ms产生一个中断没有问题,当BFIFO_DEEPTH=1的时候a_count = 4, b_count = 640, c_count = 1;

    而按照手册上的说法,a_count = 8时, b_count = 320,c_count = 1,这样每次产生的中断间隔应该是一样的,但是用示波器测出来中断间隔确实变成了2ms;

    刚才又做了一个新测试,a_count = 8, b_count = 640,c_count = 1,这样就变成了4ms一个中断,但是还是工作了2秒钟后中断就么有了。

    “为什么在设为1时,不是1/160Hz=6.25ms,而4ms是对的?”:可能是我表达的不清楚,帧同步时间是160KHz,我说的中断是一个frame传送完产生的中断,不是a_count值传送完TC产生event给CC的这个东西。

  • 实在不想讨论再多了,我自己将原来的简单工程改成了FIFO模式,可以正常工作。你自己看看吧。

    本来很简单的一件事情,越讨论越复杂。

    DSP_McBSP_demo_edma_works_withFIFO.zip
  • 谢谢您的耐心回答!

  • tony哥:

    这个FIFO的问题已经解决了,参考了你给的示例代码之后发现跟我的逻辑次序不一致,我这边是MCBSP用的是外部时钟,开FIFO的时候已经有帧同步信号了,导致工作不起来,现在把配置放到开启外部时钟之前就可以了,不是edma的配置问题。

    诶,搞了一个大乌龙。

  • 没有你的耐心解答根本完不成
  • tony哥:
    您好,有一个问题需要请教一下您,我使用am335x 的GPMC总线以EDMA方式向外部FIFO写数据,如果EDMA申请搬移的数据块大小(使用AB同步方式,设置每次传输100KB,即一个FRAME=acnt*bcnt)超过了所连接FIFO深度(8KB)的话应当怎样处理呢? 
    是否必须保证每个event的数据块小于FIFO深度?EDMA内部会不会有某种暂停机制,可以在FIFO满的时候暂停传输呢?
  • Xiwen Mei 说:
    tony哥:
    ��好,有一个问题需要请教一下您,我使用am335x 的GPMC总线以EDMA方式向外部FIFO写数据,如果EDMA申请搬移的数据块大小(使用AB同步方式,设置每次传输100KB,即一个FRAME=acnt*bcnt)超过了所连接FIFO深度(8KB)的话应当怎样处理呢? 
    是否必须保证每个event的数据块小于FIFO深度?EDMA内部会不会有某种暂停机制,可以在FIFO满的时候暂停传输呢?

    上面的参数表设置是有问题的。

    首先FIFO是有个半满信号输出的,可以将它连到GPIO做为EDMA的触发信号。

    触发一次,EDMA应该只送出FIFO一半深度的数据即4KB, 即以A同步方式,ACNT=4KB。

    而BCNT=100K/4K =25即可。

    EDMA中断设为传输完成中断。

    这样每当FIFO空出一半,发出信号触发EDMA,EDMA搬4KB数据,当FIFO再空出一半,再触发EDMA搬4KB,一共25次完成100KB数据的搬运,然后触发EDMA完成中断。

    至于ping-pong buffer的link则是另外要考虑的问题了。

  • tony哥:

    也就是说,如果现在使用AB同步方式的话,一次搬移A*B个数据,那么A*B的大小也必须与FIFO半满大小一致?这个半满信号是必须的吗?感谢您这么晚还在回复我。

  • 我认为必须,不然你如何知道什么时候可以发起数据传输,以及如何知道FIFO里有多少空余空间?FIFO一般都有半满信号,至于空或者满信号不一定有。这些信号的目的都是为了告知FIFO的状态。

    你一次传100KB,结果就是8KB之后的都丢掉了。

    你可以第一次传8KB,因为开始FIFO是空的,后面的EDMA传半FIFO的数据。看你EDMA怎么配置了。

    如果你的FIFO有空信号,那么配置EDMA每次传8KB也可以,只是这样的效率不怎么优化,因为FIFO空到有数这段间隔是没有数据传输的空闲时间。

  • Tony哥:

           抱歉昨天没有及时回复您,现在有一个现象一直困扰着我,正如您所说,我起初也是认为EDMA每次搬移的数据块大小应当满足于FIFO的深度,但是我目前所使用GPMC的EDMA方式搬移数据块大小是大于FIFO的,数据传输正常,并没有丢失,只是速度提高不明显。这里我猜测,是否是因为FPGA对FIFO读速度要远远大于ARM这边的写速度,使得即使搬移数据块大也并不会造成溢出的现象呢?

  • Xiwen Mei 说:
    是否是因为FPGA对FIFO读速度要远远大于ARM这边的写速度,使得即使搬移数据块大也并不会造成溢出的现象呢

    这个绝对可能,你说的FIFO其实是在FPGA里实现的FIFO吧。这速度当然高了。

    Xiwen Mei 说:
    只是速度提高不明显

    优化GPMC的时序。也可以用同步方式,反正对端是FPGA怎么着都行。

  • 你的mcbsp的接口是自己做的吗,能共享一下吗

  • 请问必须打开,FIFO 吗?我最近做这个,没有开FIFO,发送中断只能进一次,就不再进了,接收是好的,请问您知道是为什么吗,谢谢

  • 请问您的MCBSP 问题解决了吗