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.

Problems with eDMA in OMAP 3530

Other Parts Discussed in Thread: OMAP3530

Hi,

I using OMAP 3530 on Mistral Board and I'm having problems in run eDMA correct on Linux kernel.

- The problem is that I only receive the data on the first time the eDMA works. The following times my buffer isn't updated, staying with same data transfer at the first time. 

To simulate the eDMA working I made the  McBSP1 port send 16 data size of short and McBSP3 port to receive the data. The problema is that when I am using the eDMA only the first time I send the data is buffered in the vector. The next time I send any data the buffer isn't updated. The main loop I make the port configurations and the eDMA configuration every time.

When I using the port without eDMA I can see all the data in the internal port buffer. So the port configurations is working properly, receiving data. The code below is the code I am using to simulate and use the eDMA for reception.

 

int main_loop ()

{

      while (1)

      {

        clear_receiver_buffer ();

        configure_mcbsp1 ();

        configure_mcbsp3 ();

        send_data();

        configure_dma ();

        check_buffer ();

      }

}

// Configure McBSP1 To Transmit

configure_mcbsp1 ()

{

      BASE = 0x48074000;

 

      // Initialize McBSP1 Registers

      *(BASE + McBSP_SPCR2) = 0x00000000;

      *(BASE + McBSP_SPCR1) = 0x00000000;

 

      // Set Run Free Mode For TX And RX And Set Generation Of Interrupts

      *(BASE + McBSP_SPCR2) = 0x00000230;

      *(BASE + McBSP_SPCR1) = 0x00000020;

 

      // Set Receive Word Length To 16 Bits And 1 Bit Data Delay

      *(BASE + McBSP_RCR1) = 0x00000040;

      *(BASE + McBSP_RCR2) = 0x00000001;

 

      // Set Transmitter Word Length To 16 Bits And 1 Bit Data Delay

      *(BASE + McBSP_XCR1) = 0x00000040;

      *(BASE + McBSP_XCR2) = 0x00000001;

 

      // Set Frame Sync Mode For TX And RX And Clock Polarity

      *(BASE + McBSP_PCR) = 0x00000B00;

 

      // Set Frame Sync Width And Divide Clock By 1

      *(BASE + McBSP_SRGR1) = 0x00000000;

 

      // Setup Clock Settings And Frame Period (Time Between Frame Syncs)

      *(BASE + McBSP_SRGR2) = 0x00000040;

 

      // All Channels Enable But Masked

      *(BASE + McBSP_MCR2) = 0x00000002;

      *(BASE + McBSP_MCR1) = 0x00000001;

 

      // Enable Channel 0 To Transmit

      *(BASE + McBSP_XCERA) = 0x00000001;

 

      // Enable Channel 0 To Receive

      *(BASE + McBSP_RCERA) = 0x00000001;

 

      // Set Threshold To 0

      *(BASE + McBSP_THRSH2) = 0x00000000;

 

      // Clear All Interrupts

      *(BASE + McBSP_IRQSTATUS) = 0x00007FBF;

 

      // Enable Receive

      *(BASE + McBSP_SPCR1) |= 0x00000001;

 

      // Enables Sample Rate Generator

      *(BASE + McBSP_SPCR2) |= 0x00000040;

 

      // Enables Frame Sync Logic

      //*(BASE + McBSP_SPCR2) = *(BASE + McBSP_SPCR2) | 0x00000080;

 

      // Enables Transmitter

      //*(BASE + McBSP_SPCR2) = *(BASE + McBSP_SPCR2) | 0x00000001;

}

 

configure_mcbsp3 ()

{

      BASE = 0x49024000;

 

      // Initialize McBSP1 Registers

      *(BASE + McBSP_SPCR2) = 0x00000000;

      *(BASE + McBSP_SPCR1) = 0x00000000;

 

      // Set Run Free Mode For RX And Set Generation Of Interrupts

      *(BASE + McBSP_SPCR1) = 0x00000020;

 

      // Set Receive Word Length To 16 Bits And 1 Bit Data Delay

      *(BASE + McBSP_RCR1) = 0x00000040;

      *(BASE + McBSP_RCR2) = 0x00000001;

 

      // Set Frame Sync Mode For RX And Clock Polarity

      *(BASE + McBSP_PCR) = 0x00000000;

 

      // Set Frame Sync Width And Divide Clock By 1

      *(BASE + McBSP_SRGR1) = 0x00000000;

 

      // Setup Clock Settings And Frame Period (Time Between Frame Syncs)

      *(BASE + McBSP_SRGR2) = 0x00000040;

 

      // All Channels Enable But Masked

      *(BASE + McBSP_MCR2) = 0x00000002;

      *(BASE + McBSP_MCR1) = 0x00000001;

 

      // Enable Channel 0 To Receive

      *(BASE + McBSP_RCERA) = 0x00000001;

 

      // Set Threshold To Receive 93 Data

      *(BASE + McBSP_THRSH1) = 0x0000005C;

 

      // Clear All Interrupts

      *(BASE + McBSP_IRQSTATUS) = 0x00007FBF;

 

      // Enable Receive Interrupt

      *(BASE + McBSP_IRQENABLE) = 0x00000008;

 

      // Enable Receive

      *(BASE + McBSP_SPCR1) |= 0x00000001;

 

      // Enables Sample Rate Generator

      *(BASE + McBSP_SPCR2) |= 0x00000040;

}

configure_dma ()

{

  // Enable True Interrupt

  SYSC_LICFG0 = SYSC_LICFG0 | 0x00000100;

 

  // Select Interrupt which will trigger eDMA

  uiDMAChannel = 5;

 

  // Words amount to receiver

  usSize = 16;

 

  // Clear All Pending Interrupts From TPCC Module

  *( TPCC_ICR) = 0xFFFFFFFF;

 

  // Clear DMA Mask Bit To Work

  *( WUGEN_MEVTCLR2) |= 0x00000001 << uiDMAChannel;

 

  // Active Complete Interrupt

  *( TPCC_OPT ) = 0x00100000;

 

  // Set Interrupt To uiDMAChannel Value

  *( TPCC_OPT ) |= uiDMAChannel << 12;

 

  // Destination Start Address

  *(TPCC_DST) = (unsigned int) Receiver_Buffer;

 

  // Source Start Address (McBSP1_DRR)

  *( TPCC_SRC) = (unsigned int) BASE;

 

  // Set 8 TS To Transmit

  *(TPCC_CCNT) = 0x00000001;

 

  // Set 16 Elements (16 Word/TS) (ACNT = 4  BCNT = 16)

  *(TPCC_ABCNT) = 0x00000004;

  *(TPCC_ABCNT) |= (usSize << 16);

 

  // Set Offset To Vector

  *(PCC_BIDX) = 0x00040000;

 

  // Set Offset To Next TS

  *( TPCC_CIDX) = 0x00000000;

 

  // Enable Link

  *(TPCC_LNK) = 0x0000FFFF;

 

  // Set DMA Channel uiDMAChannel To Use PaRAM uiDMAChannel

  *( TPCC_DCHMAP ) = 0x00000000;

  *( TPCC_DCHMAP ) = uiDMAChannel << 5;

 

  // Enable Event To DMA Interrupt (EER Register)

  *(TPCC_EESR) = 0x00000001 << uiDMAChannel;

 

  // Enable DMA Channel Interrupt

  *(TPCC_IESR) = 0x00000001 << uiDMAChannel;

}

I can see the data send with a oscilloscope. Soh I know that my data is send correct.

 

When active the eDMA interrupt (TPCC_GLOBAL_INTERRUPT - Evt 29) I see (with a GPIO) that every 16 data transfer the GPIO is set.

Soh the eDMA is identifying the frame sync. But the data isn't updated in the reception buffer.

 

I simulate the same code in CCS4 with emulator XDS510 and the code work correct. Ever time I send 16 data I receive 16 data in my reception buffer.

I don't have any idea to make eDMA work in Linux kernel. In my code I am using DSP Link library I don't know if it is influencing.

 

Anyone know what is going on ?

Thanks a lot.

  • Felipe:

    The SDMA is recommended for peripheral to memory transfers.  The OMAP 3530 Tech Ref Manual has an example of SDMA configuration to transfer data between McBSP and External DRAM (Section 9.6.1.2).   Any specific reason why you would need to use EDMA instead? 

    Michael T

  •  

    Hi Michael ,

     

    I configure SDMA as you recommended but the problem is the same.

    The port configuration is OK because I can receive correct data by MCBSPLP_DRR_REG register. But the SDMA can't transfer this data to the variable.

    Is there any block / lock memory that make the SDMA fail.

     

    I am using threads in DSP side, where I call my functions to program the port and the SDMA (EDMA before). I am using DSP Link libraries also.

    Anyone can show me where is the problem ?

    Thanks a lot.

  • Philipe:

    Could you send your updated code incluing the SDMA settings?

    regards,

    Michael T

     

  •  

    Hi Michael,

     

    The updated code is the following.

     

    void fnvConfigureDmaRxIota (volatile unsigned int *BASE, short *ssBufferPtr, int uiDMAChannel, int uiDMARequest)

    {

      short usFrameSize;

     

      int uiOffset;

     

      // Number Of Elemets In A GMS Frame

      usFrameSize = 16;

     

      // Set DMA Logic Channel

      uiOffset = DMA4_OFFSET * uiDMAChannel;

     

      // Set Number Of Frames In A Block

      *( &SDMA_BASE + DMA4_CFN + uiOffset) = 0x00000001;

     

      // Set Number Of Elements In A Frames

      *( &SDMA_BASE + DMA4_CEN + uiOffset) = (usFrameSize & 0x00FFFFFF);

     

      // Set Element Size

      *( &SDMA_BASE + DMA4_CSDP + uiOffset) = 0x00000001;

     

      // Source Start Address

      *( &SDMA_BASE + DMA4_CSSA + uiOffset) = (unsigned int) BASE;

     

      // Destination Start Address

      *( &SDMA_BASE + DMA4_CDSA + uiOffset) = (unsigned int) ssBufferPtr;

     

      // Transfer is triggered by the source, Enables the supervisor mode, Selects the addressing mode from source and destination

      // An entire frame is transferred once a DMA request is made.

      *( &SDMA_BASE + DMA4_CCR + uiOffset) = 0x00000000;

      *( &SDMA_BASE + DMA4_CCR + uiOffset) = 0x01004040;

     

      // Select SDMA Channel To Be Sync (Request Line + 1)

      *( &SDMA_BASE + DMA4_CCR + uiOffset) |= ( (uiDMARequest + 1) & 0x60) << 14;

      *( &SDMA_BASE + DMA4_CCR + uiOffset) |= ( (uiDMARequest + 1) & 0x1F);

     

      // Clear All Interrupts

      *( &SDMA_BASE + DMA4_CSR + uiOffset) = 0x00001FFE;

     

      // Enable End Of Frame Interrupt

      *( &SDMA_BASE + DMA4_CICR + uiOffset) = 0x00000008;

     

      *( &SDMA_BASE + DMA4_IRQSTATUS) |= 0x00000001 << uiDMAChannel;

     

      // Clear DMA Mask Bit To Work

      *( &SDMA_BASE + DMA4_IRQENABLE) |= 0x00000001 << uiDMAChannel;

     

      // Enable Channel

      *( &SDMA_BASE + DMA4_CCR + uiOffset) |= 0x00000080;

     

      return;

    }

     

    Thanks.

  • Philipe:

    So, the code you sent is the working code and it was run without using an O/S but just running a program using CCS4?

    Does the code that uses DSP Link libraries call driver code to do the hardware initialization?

    Michael T

     

  • Philipe:

    In your McBSP1, which is the transmitter, the receiver is enabled and the enabling of the transmitter is commented out:

    configure_mcbsp1 ()

       // Enable Receive

          *(BASE + McBSP_SPCR1) |= 0x00000001;

         // Enables Transmitter

          //*(BASE + McBSP_SPCR2) = *(BASE + McBSP_SPCR2) | 0x00000001;

     

    Michael T

  • I might be jumping the gun, but this sounds a lot like a cache coherence issue.  That is, if you're receiving data from the McBSP then the first time you read that data it will be cached.  The SDMA/EDMA can then update that data in DDR but unless you manually invoke a cache invalidate you'll read back the old cached version. 

    I didn't read through all your code, so perhaps the issue is what Michael T found.  I thought I'd mention cache coherence just in case.

  •  

    Hi,

     

    So Michael the code I send to you is working in CCS4 without O/S and the DSP Link libraries don't call any driver code to do the hardware initialization.

    I use the DSP Link to create the communication between ARM and DSP and DSPBIOS to create tasks in DSP side.

    And the port enable is made when I send the data. So the problem isn't this.

     

    And Brad I think you said something important because I can see that DMA is working, reading the port information (McBSP_DRR register).

    Because I noticed that MCBSPLP_XBUFFSTAT register  from the receive port is zero , so there is no information in RB (internal receive buffer) from the port.

    I try to solve the cache coherence using BCACHE_wb (variable, size, 1) function but it didn't work.

     

    So Brad do you know how can I solve (if it is the problem) the cache coherence ? Any suggestions ?

    Thanks a lot.

     

     

  • For McBSP Receive

    • Data received by McBSP
    • Data moved by EDMA to DDR
    • CPU calls BCACHE_inv (must be BEFORE CPU accesses)
    • CPU accesses data in DDR

    For McBSP Transmit

    • Data written by CPU to DDR
    • BCACHE_wb (must be AFTER CPU accesses)
    • EDMA moves data to McBSP
    • McBSP transmits data
  •  

    Hi Brad,

     

    Thanks this work to solve the problem. When I receive the data by the EDMA I make a BCACHE_inv and the data is updated correct.

    I want to know if some change in kernel could solve this problem, because I would make BCACHE_inv every 5ms or this is not a problem ?

     

    But this work.

    Thanks a lot.

     

  • Hi Felipe,

    I will try to do the same as you have done in your post.

    Now I have an architecture question.

    Apparently you succedded to trigger the SDMA controler to transfer data. Is the transfer between the McBSP and DSP or between the McBSP and HOST?

    In case it is between McBSP and DSP, can the DSP (L3) also configure the SDMA/McBSP or should it be done from the HOST (L4)?

    Thank you.

    Fabrice.

  • Hi Fabrice,

     

    I succeed in configure McBSP port with SDMA in DSP side, without using the Host side, as the old post.

    But in DSP I could not see the interrupt signal generate by SDMA. So you can configure the SDMA in DSP side without Host , but you have to study to see if is possible to trigger the interrupt  on DSP side.

     

    If you manage to do that please post a answer here too.

     

    Thanks.

  • Felipe Souza said:
    So you can configure the SDMA in DSP side without Host , but you have to study to see if is possible to trigger the interrupt  on DSP side.

    You can get an interrupt to the DSP/IVA2.2 from SDMA_IRQ_0 and SDMA_IRQ_1.  This is shown in Table 14-3 "IVA2.2 Interrupt Mappings" in the TRM.  You need to make sure you're not trampling on channels in use by the ARM if you use the DSP to program a channel.

  • Brad and Felipe,

    Thank you for your answers.

    I still have another point to clarify. Our previous platform used the OMAP2420. There we used the SDMA and we could get DMA interrupt using the DSP/BIOS routines:


    C55_plug(C55_L2_INT3, (Fxn)dma2_hwi_isr);

    C55_plug(C55_L2_INT2, (Fxn)dma1_hwi_isr);


    It seems to be a different way to get interrupt on the DSP side right? What is the mapping of the C55_L2_INT3 and C55_L2_INT2?

    Thank you.

    Fabrice.

     

  • OMAP2420 had a 55x DSP core.  OMAP3530 has a 64x+ DSP core.  There's a similar API called C64_plug.

  • Hi Brad,

    I have another question for me to close the loop.

    1 - I understand that DSP can get data from SDMA from L3 but what make DSP to be able to access the DMA control port since it is connecte dto the L4 interconnect?

     2 - As I told you before we use the interrupt vector ID C55_L2_INT2 ( #define C55_L2_INT2 34). Where is it documented that this vector is mapped to the SDMA interrupt? Which vector ID should be used in case we use the OMAP3530 and based on the table (Table 14-3. IVA2.2 Interrupt Mappings) you pointed out?

    Thank you.

    Fabrice.

  • fabrice saadoun said:
    1 - I understand that DSP can get data from SDMA from L3 but what make DSP to be able to access the DMA control port since it is connecte dto the L4 interconnect?

    The SDMA control port is located on the L4-Core interconnect.  Table 5-14 "Connectivity Matrix" confirms that IVA2.2 can access L4-Core.

    fabrice saadoun said:
     2 - As I told you before we use the interrupt vector ID C55_L2_INT2 ( #define C55_L2_INT2 34).

    I've never used the OMAP2420 so this nugget of information is completely meaningless to me.  Sorry.  You'll have to speak in terms that relate to the OMAP3530.

    fabrice saadoun said:
    Which vector ID should be used in case we use the OMAP3530 and based on the table (Table 14-3. IVA2.2 Interrupt Mappings) you pointed out?