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.

C5509A DMA 的 ping-pong 模式



通过 McBsp + DMA 方式采集到 DSP 内存中的串行数据流需要经过 ping-pong 模式的缓存,才能保证不丢数据,实现两帧数据的无缝拼接。

请问哪里有可以参考的 DMA 的 ping-pong 模式的代码或例程?

  • C5509A DMA硬件上不支持ping pong模式。

    需要自己在软件里实现,设置两个大小一样的ping buffer, pong buffer,先是dma source address设为ping buffer, 当ping buffer满后,将dma source address设为pong buffer,依次类推。

  • 请问,下面这样写能行吗,实际测试的时候,为什么只有 rcvping[N] 里的数据在变化,而 rcvpong[N] 里面一直没有数据?

    PS:程序是将 SPI 接口的  CPLD 中的数据,经 McBsp1----->DMA1 交替采集进 ping-pong 缓存数组中。

    /*****************************************************\
    McBsp1----->DMA1----->DARAM (DSP 接收数据)
    \*****************************************************/
    #include <stdio.h>
    #include <csl_mcbsp.h>
    #include <csl_dma.h>
    #include <csl_irq.h>
    #include <csl_pll.h>
    #include <math.h>
    #include <Dsplib.h>
    #include <TMS320.H>
    #include <csl_chip.h>

    //---------Global constants---------
    #define N 256
    #define PING 0
    #define PONG 1

    static int PingPong=PING;
    unsigned long int j=0; //用来记录进入中断的次数

    //unsigned int xmtping[N];
    //unsigned int xmtpong[N];
    unsigned int rcvping[N];
    unsigned int rcvpong[N];

    //---------Global data definition---------
    /*定义一个 计数器 */
    unsigned long counter=0;

    /*锁相环的设置*/
    PLL_Config myConfig = {
    0, //IAI: the PLL locks using the same process that was underway
    //before the idle mode was entered
    1, //IOB: If the PLL indicates a break in the phase lock,
    //it switches to its bypass mode and restarts the PLL phase-locking
    //sequence
    24, //PLL multiply value; multiply 24 times
    1 //Divide by 2 PLL divide value; it can be either PLL divide value
    //(when PLL is enabled), or Bypass-mode divide value
    //(PLL in bypass mode, if PLL multiply value is set to 1)
    };

    MCBSP_Config ConfigClkstp1= {
    MCBSP_SPCR1_RMK(
    MCBSP_SPCR1_DLB_OFF, /* DLB = 0 */
    MCBSP_SPCR1_RJUST_RZF, /* RJUST = 0 */
    MCBSP_SPCR1_CLKSTP_NODELAY, /* CLKSTP = 10 */
    MCBSP_SPCR1_DXENA_ON, /* DXENA = 1 */
    MCBSP_SPCR1_ABIS_DISABLE, /* ABIS = 0 */
    MCBSP_SPCR1_RINTM_RRDY, /* RINTM = 0 */
    0, /* RSYNCER = 0 */
    MCBSP_SPCR1_RRST_DISABLE /* RRST = 0 */
    ),
    MCBSP_SPCR2_RMK(
    MCBSP_SPCR2_FREE_NO, /* FREE = 0 */
    MCBSP_SPCR2_SOFT_NO, /* SOFT = 0 */
    MCBSP_SPCR2_FRST_FSG, /* FRST = 0 */
    MCBSP_SPCR2_GRST_CLKG, /* GRST = 0 */
    MCBSP_SPCR2_XINTM_XRDY, /* XINTM = 0 */
    0, /* XSYNCER = N/A */
    MCBSP_SPCR2_XRST_DISABLE /* XRST = 0 */
    ),
    MCBSP_RCR1_RMK(
    MCBSP_RCR1_RFRLEN1_OF(0), /* RFRLEN1 = 0 */
    MCBSP_RCR1_RWDLEN1_16BIT /* RWDLEN1 = 5 */
    ),
    MCBSP_RCR2_RMK(
    MCBSP_RCR2_RPHASE_SINGLE, /* RPHASE = 0 */
    MCBSP_RCR2_RFRLEN2_OF(0), /* RFRLEN2 = 0 */
    MCBSP_RCR2_RWDLEN2_8BIT, /* RWDLEN2 = 0 */
    MCBSP_RCR2_RCOMPAND_MSB, /* RCOMPAND = 0 */
    MCBSP_RCR2_RFIG_YES, /* RFIG = 0 */
    MCBSP_RCR2_RDATDLY_0BIT /* RDATDLY = 0 */
    ),
    MCBSP_XCR1_RMK(
    MCBSP_XCR1_XFRLEN1_OF(0), /* XFRLEN1 = 0 */
    MCBSP_XCR1_XWDLEN1_16BIT /* XWDLEN1 = 5 */

    ),
    MCBSP_XCR2_RMK(
    MCBSP_XCR2_XPHASE_SINGLE, /* XPHASE = 0 */
    MCBSP_XCR2_XFRLEN2_OF(0), /* XFRLEN2 = 0 */
    MCBSP_XCR2_XWDLEN2_8BIT, /* XWDLEN2 = 0 */
    MCBSP_XCR2_XCOMPAND_MSB, /* XCOMPAND = 0 */
    MCBSP_XCR2_XFIG_YES, /* XFIG = 0 */
    MCBSP_XCR2_XDATDLY_0BIT /* XDATDLY = 0 */
    ),
    MCBSP_SRGR1_RMK(
    MCBSP_SRGR1_FWID_OF(1), /* FWID = 1 */
    MCBSP_SRGR1_CLKGDV_OF(1) /* CLKGDV = 1 */
    ),
    MCBSP_SRGR2_RMK(
    MCBSP_SRGR2_GSYNC_FREE, /* FREE = 0 */
    MCBSP_SRGR2_CLKSP_RISING, /* CLKSP = 0 */
    MCBSP_SRGR2_CLKSM_INTERNAL, /* CLKSM = 1 */
    MCBSP_SRGR2_FSGM_FSG, /* FSGM = 1 */
    MCBSP_SRGR2_FPER_OF(15) /* FPER = 0 */
    ),
    MCBSP_MCR1_DEFAULT,
    MCBSP_MCR2_DEFAULT,
    MCBSP_PCR_RMK(
    MCBSP_PCR_IDLEEN_RESET, /* IDLEEN = 0 */
    MCBSP_PCR_XIOEN_SP, /* XIOEN = 0 */
    MCBSP_PCR_RIOEN_SP, /* RIOEN = 0 */
    MCBSP_PCR_FSXM_INTERNAL, /* FSXM = 1 */
    MCBSP_PCR_FSRM_INTERNAL, /* FSRM = 1 */
    MCBSP_PCR_CLKXM_OUTPUT, /* CLKXM = 1 */
    MCBSP_PCR_CLKRM_OUTPUT, /* CLKRM = 1 */
    MCBSP_PCR_SCLKME_NO, /* SCLKME = 0 */
    0, /* DXSTAT = N/A */
    MCBSP_PCR_FSXP_ACTIVEHIGH, /* FSXP = 0 */
    MCBSP_PCR_FSRP_ACTIVEHIGH, /* FSRP = 0 */
    MCBSP_PCR_CLKXP_RISING, /* CLKXP = 0 */
    MCBSP_PCR_CLKRP_FALLING /* CLKRP = 0 */
    ),
    MCBSP_RCERA_DEFAULT,
    MCBSP_RCERB_DEFAULT,
    MCBSP_RCERC_DEFAULT,
    MCBSP_RCERD_DEFAULT,
    MCBSP_RCERE_DEFAULT,
    MCBSP_RCERF_DEFAULT,
    MCBSP_RCERG_DEFAULT,
    MCBSP_RCERH_DEFAULT,
    MCBSP_XCERA_DEFAULT,
    MCBSP_XCERB_DEFAULT,
    MCBSP_XCERC_DEFAULT,
    MCBSP_XCERD_DEFAULT,
    MCBSP_XCERE_DEFAULT,
    MCBSP_XCERF_DEFAULT,
    MCBSP_XCERG_DEFAULT,
    MCBSP_XCERH_DEFAULT
    };

    /* Create DMA Receive Side Configuration */
    DMA_Config dmaRcvConfig = {
    DMA_DMACSDP_RMK(
    DMA_DMACSDP_DSTBEN_NOBURST,
    DMA_DMACSDP_DSTPACK_OFF,
    DMA_DMACSDP_DST_DARAM,
    DMA_DMACSDP_SRCBEN_NOBURST,
    DMA_DMACSDP_SRCPACK_OFF,
    DMA_DMACSDP_SRC_PERIPH,
    DMA_DMACSDP_DATATYPE_16BIT
    ), /* DMACSDP */
    DMA_DMACCR_RMK(
    DMA_DMACCR_DSTAMODE_POSTINC,
    DMA_DMACCR_SRCAMODE_CONST,
    DMA_DMACCR_ENDPROG_ON,
    DMA_DMACCR_REPEAT_OFF,
    DMA_DMACCR_AUTOINIT_ON,
    DMA_DMACCR_EN_STOP,
    DMA_DMACCR_PRIO_HI,
    DMA_DMACCR_FS_DISABLE,
    DMA_DMACCR_SYNC_REVT1
    ), /* DMACCR */
    DMA_DMACICR_RMK(
    DMA_DMACICR_BLOCKIE_OFF,
    DMA_DMACICR_LASTIE_OFF,
    DMA_DMACICR_FRAMEIE_ON,
    DMA_DMACICR_FIRSTHALFIE_OFF,
    DMA_DMACICR_DROPIE_OFF,
    DMA_DMACICR_TIMEOUTIE_OFF
    ), /* DMACICR */
    (DMA_AdrPtr)(MCBSP_ADDR(DRR11)), /* DMACSSAL */
    0, /* DMACSSAU */
    (DMA_AdrPtr)&rcvping, /* DMACDSAL */
    0, /* DMACDSAU */
    N, /* DMACEN */
    1, /* DMACFN */
    0, /* DMACFI */
    0 /* DMACEI */
    };

    /* Define a DMA_Handle object to be used with DMA_open function */
    DMA_Handle hDmaRcv;

    /* Define a MCBSP_Handle object to be used with MCBSP_open function */
    MCBSP_Handle hMcbsp;

    //volatile Uint16 transferComplete = FALSE;
    Uint16 old_intm;
    Uint16 rcvEventId;

    //---------Function prototypes---------
    /* Reference start of interrupt vector table */
    /* This symbol is defined in file, vectors.s55 */
    extern void VECSTART(void);

    /* Protoype for interrupt functions */

    interrupt void dmaRcvIsr(void);
    void taskFxn(void);

    //---------main routine---------
    void main(void)
    {
    Uint16 i;

    /* Initialize CSL library - This is REQUIRED !!! */
    CSL_init();

    /* Set IVPD/IVPH to start of interrupt vector table */
    IRQ_setVecs((Uint32)(&VECSTART));

    /*设置系统的运行速度为144MHz*/

    PLL_config(&myConfig);

    //乒乓数组初始化
    for(i=0;i<N;i++)
    {
    rcvping[i]=0;
    rcvpong[i]=0;
    }

    /* Call function to effect transfer */
    taskFxn();
    }

    void taskFxn(void)
    {
    Uint16 srcAddrHi, srcAddrLo;
    Uint16 dstAddrHi, dstAddrLo;

    /* By default, the TMS320C55xx compiler assigns all data symbols word */
    /* addresses. The DMA however, expects all addresses to be byte */
    /* addresses. Therefore, we must shift the address by 2 in order to */
    /* change the word address to a byte address for the DMA transfer. */
    srcAddrHi = (Uint16)(((Uint32)(MCBSP_ADDR(DRR11))) >> 15) & 0xFFFFu;
    srcAddrLo = (Uint16)(((Uint32)(MCBSP_ADDR(DRR11))) << 1) & 0xFFFFu;
    dstAddrHi = (Uint16)(((Uint32)(&rcvping)) >> 15) & 0xFFFFu;
    dstAddrLo = (Uint16)(((Uint32)(&rcvping)) << 1) & 0xFFFFu;

    dmaRcvConfig.dmacssal = (DMA_AdrPtr)srcAddrLo;
    dmaRcvConfig.dmacssau = srcAddrHi;
    dmaRcvConfig.dmacdsal = (DMA_AdrPtr)dstAddrLo;
    dmaRcvConfig.dmacdsau = dstAddrHi;

    /* Open MCBSP Port 1 and set registers to their power on defaults */
    hMcbsp = MCBSP_open(MCBSP_PORT1, MCBSP_OPEN_RESET);

    /* Open DMA channels 1 */
    hDmaRcv = DMA_open(DMA_CHA1,DMA_OPEN_RESET);

    /* Get interrupt event associated with DMA receive and transmit */

    rcvEventId = DMA_getEventId(hDmaRcv);

    /* Temporarily disable interrupts and clear any pending */
    /* interrupts for MCBSP transmit */
    old_intm = IRQ_globalDisable();

    /* Clear any pending interrupts for DMA channels */

    IRQ_clear(rcvEventId);

    /* Enable DMA interrupt in IER register */

    IRQ_enable(rcvEventId);

    /* Set Start Of Interrupt Vector Table */
    IRQ_setVecs(0x10000);

    /* Place DMA interrupt service addresses at associate vector */

    IRQ_plug(rcvEventId,&dmaRcvIsr);

    /* Write values from configuration structure to MCBSP control regs */
    MCBSP_config(hMcbsp, &ConfigClkstp1);

    /* Write values from configuration structure to DMA control regs */
    DMA_config(hDmaRcv,&dmaRcvConfig);

    /* Enable all maskable interrupts */
    IRQ_globalEnable();

    /* Start Sample Rate Generator and Enable Frame Sync */
    MCBSP_start(hMcbsp,
    MCBSP_SRGR_START | MCBSP_SRGR_FRAMESYNC,
    0x300u);

    /* Enable DMA */
    DMA_start(hDmaRcv);


    /* Take MCBSP transmit and receive out of reset */
    MCBSP_start(hMcbsp,
    MCBSP_XMIT_START | MCBSP_RCV_START,
    0u);

    /************************************************\
    \************************************************/
    while(DMA_FGETH(hDmaRcv,DMACCR,ENDPROG));

    /* Wait for DMA transfer to be complete */
    while (1){
    ;
    }
    }

    //DMA1 接收中断
    interrupt void dmaRcvIsr(void)
    {

    Uint16 srcAddrHi, srcAddrLo;
    Uint16 dstAddrHi, dstAddrLo;

    DMA_FSETH(hDmaRcv,DMACSR,FRAME,0);//此句的作用是通过访问DMACSR,清零FRAME位

    /*修改DMA接收通道的目的地址,实现 ping--pong 切换*/
    //Determine which ping-pong state we're in.
    if(PingPong==PING)
    {
    srcAddrHi = (Uint16)(((Uint32)(MCBSP_ADDR(DRR11))) >> 15) & 0xFFFFu;
    srcAddrLo = (Uint16)(((Uint32)(MCBSP_ADDR(DRR11))) << 1) & 0xFFFFu;
    dstAddrHi = (Uint16)(((Uint32)(&rcvpong)) >> 15) & 0xFFFFu;
    dstAddrLo = (Uint16)(((Uint32)(&rcvpong)) << 1) & 0xFFFFu;

    dmaRcvConfig.dmacssal = (DMA_AdrPtr)srcAddrLo;
    dmaRcvConfig.dmacssau = srcAddrHi;
    dmaRcvConfig.dmacdsal = (DMA_AdrPtr)dstAddrLo;
    dmaRcvConfig.dmacdsau = dstAddrHi;

    //set new state to PONG
    PingPong=PONG;
    }
    else
    {
    srcAddrHi = (Uint16)(((Uint32)(MCBSP_ADDR(DRR11))) >> 15) & 0xFFFFu;
    srcAddrLo = (Uint16)(((Uint32)(MCBSP_ADDR(DRR11))) << 1) & 0xFFFFu;
    dstAddrHi = (Uint16)(((Uint32)(&rcvping)) >> 15) & 0xFFFFu;
    dstAddrLo = (Uint16)(((Uint32)(&rcvping)) << 1) & 0xFFFFu;

    dmaRcvConfig.dmacssal = (DMA_AdrPtr)srcAddrLo;
    dmaRcvConfig.dmacssau = srcAddrHi;
    dmaRcvConfig.dmacdsal = (DMA_AdrPtr)dstAddrLo;
    dmaRcvConfig.dmacdsau = dstAddrHi;

    //set new state to PING
    PingPong=PING;
    }

    /* Set programmation bit to 1, ENDPROG = 1) */
    DMA_FSETH(hDmaRcv,DMACCR,ENDPROG,1);
    }

  • 是所有的数据都收到ping buffer了吗?

    代码能进
    //set new state to PING
    PingPong=PING吗?

  • 每次进入DMA 接收中断,ping buffer 里的数据都会更新,而 pong buffer 里一直没有数据;

    而每次进中断 ,PingPong 的值都会有 0-1-0-1 的交替变化。

  • 是所有的数据都收到ping buffer了吗?

    当PingPong=Pong时,看一下DMA的目的地址是改成了PONG buffer首地址吗?

  • DMA的 目的地址没有变化,应该是没有切换过去。为什么会没有切换过去呢?

  • 程序能进这段代码吗?
    srcAddrHi = (Uint16)(((Uint32)(MCBSP_ADDR(DRR11))) >> 15) & 0xFFFFu;
    srcAddrLo = (Uint16)(((Uint32)(MCBSP_ADDR(DRR11))) << 1) & 0xFFFFu;
    dstAddrHi = (Uint16)(((Uint32)(&rcvpong)) >> 15) & 0xFFFFu;
    dstAddrLo = (Uint16)(((Uint32)(&rcvpong)) << 1) & 0xFFFFu;

    dmaRcvConfig.dmacssal = (DMA_AdrPtr)srcAddrLo;
    dmaRcvConfig.dmacssau = srcAddrHi;
    dmaRcvConfig.dmacdsal = (DMA_AdrPtr)dstAddrLo;
    dmaRcvConfig.dmacdsau = dstAddrHi;

  • 谢谢您的耐心解答,我又仔细看了下代码,应该是写错了,PingPong=PONG; 后,下一条语句,直接进入 else{},所以每次只进入 rcvping 接收数据,改成下面这样:

    //DMA1 接收中断

    interrupt void dmaRcvIsr(void) 
    {

    Uint16 srcAddrHi, srcAddrLo;
    Uint16 dstAddrHi, dstAddrLo;

    DMA_FSETH(hDmaRcv,DMACSR,FRAME,0);//此句的作用是通过访问DMACSR,清零FRAME位

    /*修改DMA接收通道的目的地址,实现 ping--pong 切换*/
    //Determine which ping-pong state we're in.
    if(PingPong==PING)
    {
    srcAddrHi = (Uint16)(((Uint32)(MCBSP_ADDR(DRR11))) >> 15) & 0xFFFFu;
    srcAddrLo = (Uint16)(((Uint32)(MCBSP_ADDR(DRR11))) << 1) & 0xFFFFu;
    dstAddrHi = (Uint16)(((Uint32)(&rcvpong)) >> 15) & 0xFFFFu;
    dstAddrLo = (Uint16)(((Uint32)(&rcvpong)) << 1) & 0xFFFFu;

    dmaRcvConfig.dmacssal = (DMA_AdrPtr)srcAddrLo;
    dmaRcvConfig.dmacssau = srcAddrHi;
    dmaRcvConfig.dmacdsal = (DMA_AdrPtr)dstAddrLo;
    dmaRcvConfig.dmacdsau = dstAddrHi;

    //set new state to PONG
    PingPong=PONG; 

    goto a;
    }
    else
    {
    srcAddrHi = (Uint16)(((Uint32)(MCBSP_ADDR(DRR11))) >> 15) & 0xFFFFu;
    srcAddrLo = (Uint16)(((Uint32)(MCBSP_ADDR(DRR11))) << 1) & 0xFFFFu;
    dstAddrHi = (Uint16)(((Uint32)(&rcvping)) >> 15) & 0xFFFFu;
    dstAddrLo = (Uint16)(((Uint32)(&rcvping)) << 1) & 0xFFFFu;

    dmaRcvConfig.dmacssal = (DMA_AdrPtr)srcAddrLo;
    dmaRcvConfig.dmacssau = srcAddrHi;
    dmaRcvConfig.dmacdsal = (DMA_AdrPtr)dstAddrLo;
    dmaRcvConfig.dmacdsau = dstAddrHi;

    //set new state to PING
    PingPong=PING;

    goto a;
    }

    a: 

    /* Set programmation bit to 1, ENDPROG = 1) */
    DMA_FSETH(hDmaRcv,DMACCR,ENDPROG,1);
    }

    改成这种方式后,第一次进中断后,执行  if {}, 第二次进中断后,执行 else {},依次交替。但,CDSA_L1=0x 4002;CDSA_U1= 0x 0000一直没有变化。

    也就是说,程序改成上面这样之后,虽然能交替执行 if    和  else   语句中的内容,但 DMA1 的目的地址并没有配置成功。rcvpong 中依然没有数据,不知道是什么原因?

  • 运行了下面这个pong地址赋值的语句后,dstaddr还是ping buffer的地址吗?

    dstAddrHi = (Uint16)(((Uint32)(&rcvpong)) >> 15) & 0xFFFFu;
    dstAddrLo = (Uint16)(((Uint32)(&rcvpong)) << 1) & 0xFFFFu;

    dmaRcvConfig.dmacssal = (DMA_AdrPtr)srcAddrLo;
    dmaRcvConfig.dmacssau = srcAddrHi;
    dmaRcvConfig.dmacdsal = (DMA_AdrPtr)dstAddrLo;
    dmaRcvConfig.dmacdsau = dstAddrHi;

  • 可以再最后一句程序之前加入 。

    DMA_RSETH(hDmaRcv, DMACDSAU, dstAddrHi);
    DMA_RSETH(hDmaRcv, DMACDSAL, dstAddrLo);
    DMA_start(hDmaRcv);

    你可以试试这样。