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.

No EDMA3 transfers to MCASP

I'm sure that I will recognize this as a "Doh!" question when I find the answer...  I am unable to get the EDMA3 to respond to MCASP transmit events in my 6424 application.

I have MCASP0 configured for 4 output serializers, transmitting 16-bit data padded to 32-bits in I2S output format.  The EDMA3 should constantly dump the contents of 4 sets of ping-pong buffers to the 4 serializers, using 2 linked parameter RAM sets.

My setup code is below, but the flow is

  1. Place MCASP0 in reset
  2. Configure MCASP0
  3. Request the MCASP0 XEVT EDMA3 channel
  4. Request a link channel
  5. Configure the parameter RAM sets and link them to each other
  6. Enable the EDMA3 transfer with an event trigger
  7. Take MCASP0 out of reset

After this, I see that the MCASP clocks are configured as I want them, the parameter RAM entries for the XEVT0 channel (12) and the link channel (64) look correct, and I see CH12 enabled in the EER, and TCC 12 enabled in the IER.  In MCASP0 XSTAT, I see XDATA = 1, which should generate an EDMA3 sync event.  What I don't see are any EDMA3 transfers from RAM to the MCASP :(.

QDMA transfers are working, so I think all the EDMA3 LLD configuration structures are OK.

Like I said, I'm sure the problem is obvious, but I have obviously overlooked it.  Any help would be appreciated.

The setup portion of my code follows:

    // set up MCASP0

    // First, reset the peripheral
    mcasp0Regs->GBLCTL  = 0L;    // 0 is reset default, resets everything
   
    // Set the pin directions
    mcasp0Regs->PDIR = CSL_FMKT( MCASP_PDIR_AFSX, OUTPUT )
                            | CSL_FMKT( MCASP_PDIR_ACLKX, OUTPUT )
                            | CSL_FMKT( MCASP_PDIR_AXR3, OUTPUT )
                            | CSL_FMKT( MCASP_PDIR_AXR2, OUTPUT )
                            | CSL_FMKT( MCASP_PDIR_AXR1, OUTPUT )
                            | CSL_FMKT( MCASP_PDIR_AXR0, OUTPUT );
                       
    mcasp0Regs->XMASK = 0xFFFF;    // MPEG2 decoder puts out 16-bit samples
   
    // Transmit bit stream format Register (XFMT)
   
    mcasp0Regs->XFMT = CSL_FMKT( MCASP_XFMT_XDATDLY, 0BIT )
                            | CSL_FMKT( MCASP_XFMT_XRVRS, MSBFIRST )
                            | CSL_FMKT( MCASP_XFMT_XSSZ, 32BITS )
                            | CSL_FMKT( MCASP_XFMT_XBUSEL, VBUSP )
                            | CSL_FMKT( MCASP_XFMT_XROT, 16BITS );
                       
    // Transmit Frame Sync Control Register (AFSXCTL)
    mcasp0Regs->AFSXCTL = CSL_FMK( MCASP_AFSXCTL_XMOD, 2 )    // TDM mode
                                | CSL_FMKT( MCASP_AFSXCTL_FXWID, WORD )   
                                | CSL_FMKT( MCASP_AFSXCTL_FSXM, INTERNAL );
                                                   
    // Transmit clock control register (ACLKXCTL)
    mcasp0Regs->ACLKXCTL = CSL_FMKT( MCASP_ACLKXCTL_CLKXP, RISING )
                                | CSL_FMKT( MCASP_ACLKXCTL_ASYNC, ASYNC )
                                | CSL_FMKT( MCASP_ACLKXCTL_CLKXM, INTERNAL )
                                | CSL_FMK( MCASP_ACLKXCTL_CLKXDIV, 9 );   
                                // MCASP bit clock is (SYSCLK3/(AHCLKDIV+1))/(CLKDIV+1)   
                                // Configure MCASP bit clock for 3.3 MHz
                               
    // Transmit HF Clock Control Register (AHCLKXCTL)
    // AHCLKX (and AHCLKR) must be < 40 MHz
    // AHCLKX = SYSCLK3/(AHCLKXDIV+1)
    mcasp0Regs->AHCLKXCTL = CSL_FMKT( MCASP_AHCLKXCTL_HCLKXM, INTERNAL )
                                    | CSL_FMKT( MCASP_AHCLKXCTL_HCLKXP, RISING )
                                    | CSL_FMK( MCASP_AHCLKXCTL_HCLKXDIV, 2 );
                                // AHCLK will be 33 MHz for SYSCLK1 = 594 MHz   
   
//     // Transmitter DMA Event Control Register (XEVCTL)
//     mcasp0Regs->XEVTCTL = CSL_FMKT( MCASP_XEVTCTL_XDATDMA, ENABLE );   
//     // default value
   
    mcasp0Regs->XINTCTL = CSL_FMKT( MCASP_XINTCTL_XDATA, ENABLE );
   
    // Serializer control registers 0-3
   
    CSL_FINST( mcasp0Regs->SRCTL0, MCASP_SRCTL0_SRMOD, INACTIVE );
    CSL_FINST( mcasp0Regs->SRCTL1, MCASP_SRCTL1_SRMOD, INACTIVE );
    CSL_FINST( mcasp0Regs->SRCTL2, MCASP_SRCTL2_SRMOD, INACTIVE );
    CSL_FINST( mcasp0Regs->SRCTL3, MCASP_SRCTL3_SRMOD, INACTIVE );
   
       
    // Request the MCBSP1 TX EDMA channel
    edmaAudioOutChPing = EDMA3_DRV_HW_CHANNEL_MCASP0_TX;

    // Also a link channel - get a link PaRAM set
    edmaAudioOutChPong = EDMA3_DRV_LINK_CHANNEL;
     
    // Request the ping channel first
     
    edma3Result = EDMA3_DRV_requestChannel( hEdma, &edmaAudioOutChPing, &edmaTccPing,
             (EDMA3_RM_EventQueue)1, &callback2, NULL );
           
   
    if( edma3Result != EDMA3_DRV_SOK )
      {
          LOG_printf( &LOG_User, "EDMA3_DRV_requestChannel failed: %d",
                edma3Result );
        goto end;
      }

    // Request the link channel
   
    edma3Result = EDMA3_DRV_requestChannel( hEdma, &edmaAudioOutChPong, &edmaTccPong,
            (EDMA3_RM_EventQueue)0, &callback2, NULL );
   
    // Configure the EDMA3 channels
   
    // First, initialize structures in RAM to contain the configuration
   
    // Channel options are the same for the primary and the link channel
    // except for the TCC value
   
    // channel options are:
    //                                no chaining
    //                                no intermediate transfer complete interrupt
    //                                interrupt on transfer complete
    //                                normal TC interrupt (not early)
    //                                32-bit output fifo
    //                                parameter set isn't static
    //                                use AB synchronization
    //                                increment dest address across MCASP XBUFn
    //                                increment source address
   
    edma3PaRAMValsPing.OPT = CSL_FMKT( EDMA3CC_OPT_ITCCHEN, DISABLE )
                                    | CSL_FMKT( EDMA3CC_OPT_TCCHEN, DISABLE )
                                    | CSL_FMKT( EDMA3CC_OPT_ITCINTEN, DISABLE )
                                    | CSL_FMKT( EDMA3CC_OPT_TCINTEN, ENABLE )
                                    | CSL_FMK( EDMA3CC_OPT_TCC, edmaTccPing )
                                    | CSL_FMKT( EDMA3CC_OPT_TCCMOD, NORMAL )
                                    | CSL_FMKT( EDMA3CC_OPT_FWID, RESETVAL )
                                    | CSL_FMKT( EDMA3CC_OPT_STATIC, NORMAL )
                                    | CSL_FMKT( EDMA3CC_OPT_SYNCDIM, ABSYNC )
                                    | CSL_FMKT( EDMA3CC_OPT_DAM, CONST )
                                    | CSL_FMKT( EDMA3CC_OPT_SAM, INCR );

    edma3PaRAMValsPong.OPT = CSL_FMKT( EDMA3CC_OPT_ITCCHEN, DISABLE )
                                    | CSL_FMKT( EDMA3CC_OPT_TCCHEN, DISABLE )
                                    | CSL_FMKT( EDMA3CC_OPT_ITCINTEN, DISABLE )
                                    | CSL_FMKT( EDMA3CC_OPT_TCINTEN, ENABLE )
                                    | CSL_FMK( EDMA3CC_OPT_TCC, edmaTccPong )
                                    | CSL_FMKT( EDMA3CC_OPT_TCCMOD, NORMAL )
                                    | CSL_FMKT( EDMA3CC_OPT_FWID, RESETVAL )
                                    | CSL_FMKT( EDMA3CC_OPT_STATIC, NORMAL )
                                    | CSL_FMKT( EDMA3CC_OPT_SYNCDIM, ABSYNC )
                                    | CSL_FMKT( EDMA3CC_OPT_DAM, CONST )
                                    | CSL_FMKT( EDMA3CC_OPT_SAM, INCR );       
                                   
   
    // Set the starting address for the transfers
    // this starts with the PING buffer   
    edma3PaRAMValsPing.SRC = ( Uint32 )&output0SyncPing;
   
    // This one starts with the PONG buffer
    edma3PaRAMValsPong.SRC = ( Uint32 )&output0SyncPong;
   
    // Each MCASP EDMA transmit event moves 2 bytes per channel (ACNT)
    // for each of 4 channels (BCNT)
    edma3PaRAMValsPing.A_B_CNT = CSL_FMK( EDMA3CC_A_B_CNT_ACNT, 2 )
                                        | CSL_FMK( EDMA3CC_A_B_CNT_BCNT, 4 );
                                                                    
    edma3PaRAMValsPong.A_B_CNT = edma3PaRAMValsPing.A_B_CNT;
   
    // Transfer starts with MCASP0_XBUF0
    edma3PaRAMValsPing.DST = CSL_MCASP_TXBUF_ADDR;
    edma3PaRAMValsPong.DST = CSL_MCASP_TXBUF_ADDR;
   
    // source and destination B indices
    // These are the distance in bytes between the start of
    // B-dimension transfers
   
    edma3PaRAMValsPing.SRC_DST_BIDX =
            CSL_FMK( EDMA3CC_SRC_DST_BIDX_DSTBIDX, 0 )   
            | CSL_FMK( EDMA3CC_SRC_DST_BIDX_SRCBIDX,
                        (Uint16)(sizeof( tAudioSync ) + sizeof( output0BufferPing )));
               
    edma3PaRAMValsPong.SRC_DST_BIDX = edma3PaRAMValsPing.SRC_DST_BIDX;
   
    // Get the physical address of the PING parameter RAM set
    edma3Result = EDMA3_DRV_getPaRAMPhyAddr( hEdma, edmaAudioOutChPing,
            &paRAMSetPingAddress );
   
    if( edma3Result != EDMA3_DRV_SOK )
      {
      LOG_printf( &LOG_User, "Getting PING paRAM address failed, %d",
                      edma3Result );
        goto end;       
      }
           
    // Get the physical address of the PONG parameter RAM set

    edma3Result = EDMA3_DRV_getPaRAMPhyAddr( hEdma, edmaAudioOutChPong,
            &paRAMSetPongAddress );
   
    if( edma3Result != EDMA3_DRV_SOK )
      {
      LOG_printf( &LOG_User, "Getting PONG paRAM address failed, %d",
                      edma3Result );
        goto end;       
      }

    // Link the PARAM sets - PING to PONG, PONG to PING
    edma3PaRAMValsPing.LINK_BCNTRLD = CSL_FMK( EDMA3CC_LINK_BCNTRLD_BCNTRLD, 4 )
            | CSL_FMK( EDMA3CC_LINK_BCNTRLD_LINK, (Uint16)paRAMSetPongAddress );
     
   
    edma3PaRAMValsPong.LINK_BCNTRLD = CSL_FMK( EDMA3CC_LINK_BCNTRLD_BCNTRLD, 4 )
            | CSL_FMK( EDMA3CC_LINK_BCNTRLD_LINK, (Uint16)paRAMSetPingAddress );
               
   

    // Set the source and destination C indices
    // C index is the distance between the beginning of consecutive frames
    // in the AB synchronized transfer
    edma3PaRAMValsPing.SRC_DST_CIDX = CSL_FMK( EDMA3CC_SRC_DST_CIDX_SRCCIDX, 4 )
                                                | CSL_FMK( EDMA3CC_SRC_DST_CIDX_DSTCIDX, 0 );
                                           
    edma3PaRAMValsPong.SRC_DST_CIDX = edma3PaRAMValsPing.SRC_DST_CIDX;       
   
    edma3PaRAMValsPing.CCNT = ((( FRAME_LEN * MAX_CHANNELS)/sizeof(CT_int16))
                                    + (( sizeof( tAudioSync  )/sizeof( Uint16 ))));
                                           
    edma3PaRAMValsPong.CCNT = edma3PaRAMValsPing.CCNT;
   
    LOG_printf( &LOG_User, "EDMA3_DRV_requestChannel succeeded." ); 
   
    // Now, configure the actual EDMA PARAM sets
   
    edma3Result = EDMA3_DRV_setPaRAM( hEdma, edmaAudioOutChPing,
            ( const EDMA3_DRV_PaRAMRegs *)&edma3PaRAMValsPing );
   
    if( edma3Result != EDMA3_DRV_SOK )
      {
      LOG_printf( &LOG_User, "Configuring PING PARAM failed, %d",
                  edma3Result );
        goto end;       
      }
   
    edma3Result = EDMA3_DRV_setPaRAM( hEdma, edmaAudioOutChPong,
            ( EDMA3_DRV_PaRAMRegs *)&edma3PaRAMValsPong );
   
    if( edma3Result != EDMA3_DRV_SOK )
      {
      LOG_printf( &LOG_User, "Configuring PONG PARAM failed, %d",
                  edma3Result );
        goto end;       
      }           
   
    // Link the two parameter sets to each other
   
    edma3Result = EDMA3_DRV_linkChannel( hEdma,
                            edmaAudioOutChPing,
                            edmaAudioOutChPong ); 
                           
   
    if( edma3Result != EDMA3_DRV_SOK )
      {
      LOG_printf( &LOG_User, "Linking PONG to PING failed, %d",
                  edma3Result );
        goto end;       
      }
   
    edma3Result = EDMA3_DRV_linkChannel( hEdma,
                            edmaAudioOutChPong,
                            edmaAudioOutChPing ); 
                           
   
    if( edma3Result != EDMA3_DRV_SOK )
      {
      LOG_printf( &LOG_User, "Linking PING to PONG failed, %d",
                  edma3Result );
        goto end;       
      }
   
    // Clear any error flags from XSTAT
    mcasp0Regs->XSTAT = CSL_FMKT( MCASP_XSTAT_XERR, ERROR )
                                | CSL_FMKT( MCASP_XSTAT_XDMAERR, ERROR )
                                | CSL_FMKT( MCASP_XSTAT_XSTAFRM, YES )
                                | CSL_FMKT( MCASP_XSTAT_XDATA, YES )
                                | CSL_FMKT( MCASP_XSTAT_XCKFAIL,YES )
                                | CSL_FMKT( MCASP_XSTAT_XSYNCERR, YES )
                                | CSL_FMKT( MCASP_XSTAT_XUNDRN, YES );
     
    EDMA3_DRV_enableTransfer( hEdma, edmaAudioOutChPing, EDMA3_DRV_TRIG_MODE_EVENT );
   
        // Take the Serializers out of reset
   
    CSL_FINST( mcasp0Regs->SRCTL0, MCASP_SRCTL0_SRMOD, XMT );
    CSL_FINST( mcasp0Regs->SRCTL1, MCASP_SRCTL1_SRMOD, XMT );
    CSL_FINST( mcasp0Regs->SRCTL2, MCASP_SRCTL2_SRMOD, XMT );
    CSL_FINST( mcasp0Regs->SRCTL3, MCASP_SRCTL3_SRMOD, XMT );

   
    // Take the MCASP out of reset and let it run
    mcasp0Regs->XGBLCTL = CSL_FMKT( MCASP_XGBLCTL_XFRST, ACTIVE )
                                | CSL_FMKT( MCASP_XGBLCTL_XSMRST, ACTIVE )
                                | CSL_FMKT( MCASP_XGBLCTL_XSRCLR, ACTIVE )
                                | CSL_FMKT( MCASP_XGBLCTL_XHCLKRST, ACTIVE )
                                | CSL_FMKT( MCASP_XGBLCTL_XCLKRST, ACTIVE );         
                  
   

  • Just a few quick comments, not necessarily solving the problem yet:

    1. You should set OPT.DAM to INCR even though you want to keep the address constant. The Constant Addressing mode is misleading and I am pretty sure it is not intended for the McASP peripheral. If you set OPT.DAM=INCR and keep both DSTxIDX=0, you will accomplish the same intention.
    2. For ping/pong buffering, you need to use three Param Sets. One for the active channel that will start as ping, one as a link set (IMO, it should not be called a link channel, but the LLD does call it that) for the pong buffer, and one as a link set for the ping buffer. In the Training section of TI.com, there is a training video set for the C6474. The EDMA3/QDMA/IDMA Module has a section that talks about ping/pong buffers, "Example #2 - Multiple Block Transfer". You can find the complete video set at http://focus.ti.com/docs/training/catalog/events/event.jhtml?sku=OLT110002 .
    3. Your settings for SRCBIDX and CCNT are not clear to me, especially since they have terms added to make the final value. It probably just means that I do not understand your buffer structure. But SRCBIDX should be the distance from byte0 of the first data for Serializer 0 to byte0 of the first data for Serializer 1. And CCNT should be the number of samples of data in each serializer's ping buffer.
    4. Your settings for ACNT=2 and SRCCIDX=4 means that your data is 16-bits but not packed within the ping buffer. If this is correct, then at least I am not confused on those.
    5. Since you are directly writing to LINK_BCNTRLD, you do not have to also do the linkChannel call. Or you could skip the writes to LINK_BCNTRLD and just do the linkChannel calls. BCntRld is not used when you have OPT.SYNCDIM=ABSYNC, so either method is fine.
    6. Both the active Param Set and the link Param Sets should have OPT.TCC=12. This is assuming you want to throw the same IPR bit for an interrupt when either ping or pong completes. If they are supposed to be different so you can distinguish between the two, then you will need to avoid the linkChannel calls because they have a side-effect of forcing the same OPT.TCC value for both Param Sets; or correct for that "feature" after the call.
    7. To clarify a little about #5 and #6, you do not want to have the pong Param Set linking back to the active Param Set, no matter which way you program it. Hopefully the EDMA video will help explain this better.

    It is possible that your data problem is related to some of the above, but I would have expected you to get one buffer transmitted and possibly a second, rather than none.

    My first thought was that you need to force the first EDMA event as a manual event (writing to ESR), this is from assuming that XDATA=1 did not transition from 0 to 1 to trigger an event. I am not sure what the proper EDMA3 LLD method is for doing this, but you might be able to write to ESR.bit12 from CCS to kick it off and see if it starts running.

  • Hi, Randy,

    thanks for the help.

    I fixed the CONST addressing mode.  I'm not really sure what it's for, but I changed now have DSTAM = INCR with B and C indices set to zero.

    Thanks also for reminding me about needing 3 param sets for the ping-pong buffers - I should have remembered that, but I'm grateful for collective memory.

    I think my settings for SRCBIDX, SRCIDX, ACNT, and BCNT are now right.  I am sending 16-bit values to the MCASP, which should pack them to 32 bits in the I2S frame.  I now have:

    SRCBIDX as the distance between the start of consecutive arrays,
    SRCIDX = 2
    ACNT = 2
    BCNT = 4
    CCNT = number of  frames

    The writes to LINK_BCNTRLD are artifacts of an earlier test.  The EDMA3_DRV_requestChannel( ) function doesn't return a TCC when you ask for a link channel.  I don't know if that was intended, but I  can deal with sorting the current transfer out.

    I found one MCASP clocking problem - I wasn't clearing the initial XCKFAIL, so the MCASP never generated any EDMA events.  After I discovered that, and corrected the other issues, I have some improvement.  Now the MCASP appears to be generating one EDMA event, after which I see XUNDRN getting set in XSTAT.  The CCNT field in the PARAM shows that it handled one transfer. 

    I have seen some other posts on problems with MCASP transmit underrun, but they all appeared to be related to emulation halts, but I'm seeing the stall whether or not I let the emulator halt the processor.   Any ideas on that?

     

     

     

  • Can you post the current McASP initialization code for review?  Please attach under the "options" menu rather than pasting into the window.  It's hard to read code on the forum.  Also, who is the master?

  • Brad,

    I got the problem resolved, and I have attached my MCASP and EDMA3 initialization code in the hopes that it will save someone else a few days of head scratching.  I pulled out all the headers and variable declarations because they contained some proprietary references, but it should still be helpful.  I used the register-level CSL from PSP 1.10.03 and the EDMA3 LLD 1.10.0.1.

    It's necessary to slavishly follow the procedure in section 2.10.2 of the TMS320C642x DSP Multichannel Audio Serial Port (McASP) User's Guide (SPRUEN1C) with regard to configuring the MCASP clocks and taking the MCASP out of reset.  I hadn't done that :(.

  • Thanks for the reply and for saving others the headaches!  I've run into this issue with other customers in the past.  It's important to make sure that the transmitter doesn't underflow on startup.  Once it underflows you're done for!

  • Jim,

    I am surprised that you do not need to have three calls to linkChannel. There may be a side-effect somewhere that I am missing, but I would have expected to need to also add

    edma3Result = EDMA3_DRV_linkChannel( hEdma,
                                         edmaAudioOutChPingLink,
                                         edmaAudioOutChPong );

    This would provide the link at the end of the 3rd buffer (ping, pong, pingLink, pong, ...). But if it is working past the 3rd buffer, then I am obviously missing something.

  • Randy,

    Thanks for catching that.  You're right, the third link to EDMA3_DRV_LinkChannel is missing.  I probably would have figured out that something was missing when I really started looking at  the output data.  I was so excited to see bits coming out on the MCASP pins that I forgot to put it in.

  • Jim, Randy,

    Thanks for the thorough post.

    Jim...does your snippit include the suggested changes?

    thx

    MikeH

     

  • Mike,

    It's been a while since I looked at this, but I believe that the code snippet that I posted does need the additional link that Randy suggested.  I fixed it in the application, but I didn't  post the new code.

    Good luck,

    Jim

  • Jim, Tanks for the update.