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.

SPI receive complete to triggered DMA transfer large delay



 

Hi,

I have an issue with DMA time to service from request which I hope someone can help me with.

I have an SPI receive transfer which I am using to trigger a DMA transfer of received data into a RAM buffer. On DMA frame transfer complete interrupt I activate a 'service routine'. By driving a DIO pin from within this service routine and using a scope to view SPI chip select and DIO pin, I can see that the service routine is activated at time t_dma = 31.2us from end of SPI chip select (see following diagram).

The issue I have is that this is an incredibly long time. I think the DMA transfer itself only takes a microsecond or two, and it is its start which is being delayed by some 30us from end of SPI transfer. Why is this?

   ________
  |        |
__|        |_______________________________________________ SPI CS
           .
           .                                    ____
           .                                   |    |
_______________________________________________|    |______ Service Routine Active
           .                                   .
           .<------------- t_dma ------------->.

t_dma = 31.2us

As a comparison, I have called the service routine directly from the SPI receive complete interrupt (this interrupt was not active in the first scenario above). In this case, I can see that the service routine is activated at time t_spi = 1.2us from end of SPI chip select (see following diagram).

   ________
  |        |
__|        |_______________________________________________ SPI CS
           .
           .            ____
           .           |    |
_______________________|    |______________________________ Service Routine Active
           .           .
           .<- t_spi ->.

t_spi = 1.2us

Regards, Tony.

 

  • Hi Tony,

    I'm consulting on this point with our design team.

    By the way in case 1 what timings you would get if you call the DIO pin toggle routine once the SPI receive falg is set (instead of the DMA frame complete interrupt).

    Best Regards,

    Pratip

  • Hi Pratip,

    I'm not quite sure what you're asking for. My case 2 illustrates what the time from end of SPI receive (i.e. receive complete) straight to ISR would be. I would expect the DMA in case 1 to be started in much the same time as the SPI interrupt in case 2, i.e. one or two microseconds. I think the DMA operation itself takes something in the order of 1us, it is only transferring some 8 16-bit words.

    Regards, Tony.

  • Hi Pratip,

    An additional experiment I've just tried. If I activate the DMA transfer by software from the SPI receive interrupt of case 2, then the DMA frame transfer complete occurs within 2.5us from the SPI receive interrupt.

       ________
      |        |
    __|        |_______________________________________________ SPI CS
               .
               .            ____
               .           |    |
    _______________________|    |______________________________ SPI Receive Complete ISR
               .           .    .
               .<- t_spi ->.    .
                                .                   ____
                                .                  |    |
    _______________________________________________|    |______ DMA Frame Transfer Complete ISR
                                .                  .
                                .<---- t_dma ----->.

    t_spi = 1.2us
    t_dma = 2.5us

    Regards, Tony.

  • Tony,

    Okay. So you are transfering a very few data packets. I see the point.

    Infact the call to the interrupt and the DMA both happen at the same time. So ideally no delay is expected in starting the DMA for sure.

    The only area that we can doubt is, if the DMA is loaded with any other operation at higher priority than this SPI receive data transfer that keeps the DMA controller busy.

    Best Regards,

    Pratip

  • Hi Pratip,

    Unfortunately, this is the only DMA I have configured and running, so DMA busy is not the explanation. And from my example, you can see that DMA software activated from SPI receive complete ISR is not delayed, whilst DMA hardware activated directly from SPI receive complete is delayed.

    Is there any requirement for me to configure the DMA settings available within the SPI module which would impact on its priority?

    Regards, Tony.

  • Hi,

    I wonder if anybody at TI can perform a quick evaluation to see if my problem is reproducible. I would really like to find a better solution that my current one (generate an FIQ which itself starts the DMA).

    Regards, Tony.

  • Hi,

    Would you be able to provide the SPI and DMA settings code to have a look ?

    Regards,

    Pratip

  • Hi Pratip,

    This code is embedded within a larger project which is subject to NDA. I would rather, however, that TI were able to try and reproduce this with a much simpler project to see whether it is most likely something to do with my particular project, or hether it is a more fundemental problem with the TMS570. If TI would rather I try with a simple project then I can, I just thought you would have many simple example projects which could be easily modified.

    Let me know if you would like me to try a simpler project here first.

    Regards, Tony.

  • Tony,

    I was just looking for a code snippet or register settings of DMA and SPI .

    Let me try and extraxt a code snippet of the SPI DMA settings from my side meanwhile.

     

    Regards,

    Pratip

  • Hi Tony,

    1) When you are using SPI RX DMA hope you have not enabled any SPI receive buffer Full Interrupt. 
    2) Can you pls send us the DMA control packet configuration( i.e FRAME TRANSFER, SIZE info, SOURCE, AUTOINIT on/off etc) used.

    Best Regards
    Prathap

     

  • Hi Pratip,

    1) I don't have SPI RXBUF FULL interrupt enabled when trying to get SPI RX DMA working.

    2) My DMA settings are:

    (regSpi[SPI_MODULE_1_E]).DMAxCTRL[0] = 0x00008000;  /* SPI DMA Channel Control Register (DMAxCTRL)
                                                        0000 0000 0000 0000 1000 0000 -000 0000
                                                        0                                       ONESHOT
                                                         000 0000                               BUFIDx
                                                                  0000                          RXDMA_MAPx
                                                                       0000                     TXDMA_MAPx
                                                                            1                   RXDMAENAx
                                                                             0                  TXDMAENAx
                                                                              0                 NOBRKx
                                                                               0 0000           ICOUNTx
                                                                                       0        COUNTBIT17x
                                                                                        00 0000 COUNTx */

    sctChanConfig.enumRequestLine          = DMA_REQ_1_E;
    sctChanConfig.enumChannel              = DMA_CHAN_1_E;
    sctChanConfig.enumPriority             = DMA_PRIORITY_HIGH_E;
    sctChanConfig.nSourceAddress           = (uint32)&(((ramSpi[SPI_RAM_1_E]).RXRAM)[0]).SPIRXDATA;
    sctChanConfig.nDestinationAddress      = (uint32)&nSpi1RxBuf_M[nSpi1RxBufNew_M][0];
    sctChanConfig.enumSrcAddrControl       = DMA_ADDR_OFFSET_E;
    sctChanConfig.enumDestAddrControl      = DMA_ADDR_INC1_E;
    sctChanConfig.enumReadAccessBit        = DMA_ACCESS_16_BIT_E;
    sctChanConfig.enumWriteAccessBit       = DMA_ACCESS_16_BIT_E;
    sctChanConfig.enumTransferType         = DMA_FRAME_TRANSFER_E;
    sctChanConfig.enumAutoInit             = DMA_AUTOINIT_ON_E;
    sctChanConfig.nFrameCount              = 1U;
    sctChanConfig.nElementCount            = 9U;
    sctChanConfig.nChainChannel            = DMA_CHAN_2_E + 1U;
    sctChanConfig.nReadElementIndexOffset  = 4U;
    sctChanConfig.nWriteElementIndexOffset = 0U;
    sctChanConfig.nReadFrameIndexOffset    = 0U;
    sctChanConfig.nWriteFrameIndexOffset   = 0U;
    sctChanConfig.enumFTCInt               = DMA_INT_DISABLE_E;
    sctChanConfig.fnFTCIsrPtr              = (StdFnVoidPtr_T)NULL_PTR;
    sctChanConfig.enumLFSInt               = DMA_INT_DISABLE_E;
    sctChanConfig.fnLFSIsrPtr              = (StdFnVoidPtr_T)NULL_PTR;
    sctChanConfig.enumHBCInt               = DMA_INT_DISABLE_E;
    sctChanConfig.fnHBCIsrPtr              = (StdFnVoidPtr_T)NULL_PTR;
    sctChanConfig.enumBTCInt               = DMA_INT_DISABLE_E;
    sctChanConfig.fnBTCIsrPtr              = (StdFnVoidPtr_T)NULL_PTR;

    (regDma.HWCHENAS) |= ((uint32)1U << 1);          /* Enable channel */
    The DMA parameters are set in one of our defined structures, but I'm sure you can see what values go into which registers, but here is a guide:
    ((ramDma.DMAPCR)[enumChanIndex]).ISADDR = sctChanConfigPtr->nSourceAddress;
    ((ramDma.DMAPCR)[enumChanIndex]).IDADDR = sctChanConfigPtr->nDestinationAddress;
    ((ramDma.DMAPCR)[enumChanIndex]).ITCOUNT = (uint32)sctChanConfigPtr->nFrameCount << BITS_PER_SHORT;
    (((ramDma.DMAPCR)[enumChanIndex]).ITCOUNT) |= (uint32)sctChanConfigPtr->nElementCount;
    (((ramDma.DMAPCR)[enumChanIndex]).CHCTRL) = ((uint32)sctChanConfigPtr->enumSrcAddrControl << N_SRC_ADDRESS_OFFSET_C);
    (((ramDma.DMAPCR)[enumChanIndex]).CHCTRL) |= ((uint32)sctChanConfigPtr->enumDestAddrControl << N_DEST_ADDRESS_OFFSET_C);
    (((ramDma.DMAPCR)[enumChanIndex]).CHCTRL) |= ((uint32)sctChanConfigPtr->enumTransferType << BITS_PER_BYTE);
    (((ramDma.DMAPCR)[enumChanIndex]).CHCTRL) |= ((uint32)sctChanConfigPtr->enumReadAccessBit << N_READ_ACCESS_OFFSET_C);
    (((ramDma.DMAPCR)[enumChanIndex]).CHCTRL) |= ((uint32)sctChanConfigPtr->enumWriteAccessBit << N_WRITE_ACCESS_OFFSET_C);
    (((ramDma.DMAPCR)[enumChanIndex]).CHCTRL) |= sctChanConfigPtr->enumAutoInit;
    (((ramDma.DMAPCR)[enumChanIndex]).CHCTRL) |= ((uint32)sctChanConfigPtr->nChainChannel << BITS_PER_SHORT);
    (((ramDma.DMAPCR)[enumChanIndex]).EIOFF) = (((uint32)sctChanConfigPtr->nWriteElementIndexOffset << BITS_PER_SHORT) | ((uint32)sctChanConfigPtr->nReadElementIndexOffset));
    (((ramDma.DMAPCR)[enumChanIndex]).FIOFF) = (((uint32)sctChanConfigPtr->nWriteFrameIndexOffset << BITS_PER_SHORT) | (sctChanConfigPtr->nReadFrameIndexOffset));
     
    if(DMA_INT_ENABLE_E == sctChanConfigPtr->enumFTCInt)
    {
        (regDma.FTCINTENAS) |= ((uint32)1U << enumChanIndex);
         fnDmaIsrListPtr_M[DMA_FTC_INT_E][enumChanIndex] = sctChanConfigPtr->fnFTCIsrPtr;
    }

    if(DMA_INT_ENABLE_E == sctChanConfigPtr->enumLFSInt)
    {
        (regDma.LFSINTENAS) |= ((uint32)1U << enumChanIndex);
         fnDmaIsrListPtr_M[DMA_LFS_INT_E][enumChanIndex] = sctChanConfigPtr->fnLFSIsrPtr;
    }
        
    if(DMA_INT_ENABLE_E == sctChanConfigPtr->enumHBCInt)
    {
        (regDma.HBCINTENAS) |= ((uint32)1U << enumChanIndex);
         fnDmaIsrListPtr_M[DMA_HBC_INT_E][enumChanIndex] = sctChanConfigPtr->fnHBCIsrPtr;
    }
        
    if(DMA_INT_ENABLE_E == sctChanConfigPtr->enumBTCInt)
    {
        (regDma.BTCINTENAS) |= ((uint32)1U << enumChanIndex);
         fnDmaIsrListPtr_M[DMA_BTC_INT_E][enumChanIndex] = sctChanConfigPtr->fnBTCIsrPtr;
    }
        
    if((DMA_INT_ENABLE_E == sctChanConfigPtr->enumFTCInt) || (DMA_INT_ENABLE_E == sctChanConfigPtr->enumLFSInt) ||
        (DMA_INT_ENABLE_E == sctChanConfigPtr->enumHBCInt) || (DMA_INT_ENABLE_E == sctChanConfigPtr->enumBTCInt))
    {
        (regDma.GCHIENAS) |= ((uint32)1U << enumChanIndex);      /** DMA Global Interrupt Enable Set Register */
    }
      
    /* Set channel to high-priority queue if request */
    if(DMA_PRIORITY_HIGH_E == sctChanConfigPtr->enumPriority)
    {
        (regDma.CHPRIOS) |= ((uint32)1U << enumChanIndex);
    }
    Thanks for your continued help, regards, Tony.

  • Hi Tony,

    Looking at the code I think you are using DMA with MIBSPI mode not SPI Mode( Compatibility Mode)... i.e.. MibSPI ENA bit in MIBSPIE register(offset 0x70) in the module is set to 1, Am I right? My earlier comment was under assumption that you are using the module in Compatibility Mode( Just SPI)  

    Are you trying to receive 9 - 16bit data and generate DMA request to transfer it to System RAM? or for every 16bit data received you want DMA to transfer? I see you have configured as Frame transfer with Element count as 9, so FRAME complete interrupt will occur only after 9 16 bit datas are transfered.

    If you want to transfer 9 - 16 Bit valid SPI data then try using MIBSPI buffer 9 (using BUFID in (regSpi[SPI_MODULE_1_E]).DMAxCTRL[0])  to trigger DMA request, so that after receiving all 9 16bit SPI data in the RX RAM a DMA trigger will occur and will transfer data from Buffer 0 (since in DMA control packet source is RXRAM 0) to 9 to the destination system RAM. Using AUTOINIT and frame offset if required,  you can use the same configuration to receive multiple frames.

    Why are you using DMA channel chaining? Is it for other purpose or same SPI transfer? Just trying to understand.

    If I get the exact useage I can help you with better solution.

    I am adding you as my friend to support if something specific you want to share.

    Best Regards
    Prathap

  • Hi Prathap,

    You're right, I'm not using SPI Compatibility mode. the MIBSPI provides some useful benefits I think that I wouldn't otherwise get (particularly memory fault protection and DMA interface).

    My scenario is described in other forum post Re: Complex SPI, DMA, CRC, RTI, FIQ integration scenario. Basically, I am receiving a 9*16-bit transfer which must be transferred from RXRAM to to my own circular RAM buffer; this must then CRC'd before being made available to my application as valid, and its exact time of receipt must be recorded. I must also prepare the responding transmit data which must be copied to SPI TXRAM from an internal RAM buffer, and a CRC added. I'll send you diagram of my Master and Slave requirements (termed Primary and Secondary here) for your interest.

    You will see from yet another forum post that I am having trouble with data receipt, Re: SPI Receive RXRAM all-zero without XDS510 connected. Sunil is helping me with this, but if you have any ideas!

    Regards, Tony.

     

  • Hi Prathap,

    As discussed in conversation, this problem seems to have been resolved by hardware swap-out. I am happy for this post to be regarded as closed.

    Regards, Tony.