2 Replies Latest reply on May 7, 2019 6:39 AM by LePo_1062026

    DMA interrupt repeatedly called

    josc_1234441

      I am using the following code to setup a double-buffering scheme for the ADC. It appears that the DMA ISR is repeatedly being called rather than when 32 samples have been transferred. If I add the line: CyDmaClearPendingDrq(DMA_1_Chan); then it never gets called.

      What could be wrong?

       


      #include <project.h>

      #include "adc_dma.h"

      #include "idac.h"


      #define NSAMPLES 32

      #define TFR_CNT NSAMPLES * 2

      #define DMA_BYTES_PER_BURST 2

      #define DMA_REQUEST_PER_BURST 1

      #define DMA_SRC_BASE (CYDEV_PERIPH_BASE)

      #define DMA_DST_BASE (CYDEV_SRAM_BASE)


      uint8 DMA_1_Chan; //TODO: use the int assigned in DMA_1_dma.h

      uint8 DMA_1_TD[2];

      uint16_t adc_buffer1[NSAMPLES] ={0};

      uint16_t adc_buffer2[NSAMPLES] ={0};

      //static volatile uint16_t total;

      uint16_t adc_val = 0;

      uint8 currentTD = 0;

      uint16_t last_total;


      void init_adc_dma(void) {

       

        DMA_1_Chan = DMA_1_DmaInitialize(DMA_BYTES_PER_BURST, DMA_REQUEST_PER_BURST, HI16(DMA_SRC_BASE), HI16(DMA_DST_BASE));

        DMA_1_TD[0] = CyDmaTdAllocate();

        DMA_1_TD[1] = CyDmaTdAllocate();

        CyDmaTdSetConfiguration(DMA_1_TD[0], TFR_CNT, DMA_1_TD[1],

        TD_INC_DST_ADR | TD_AUTO_EXEC_NEXT | TD_TERMOUT0_EN | DMA_1__TD_TERMOUT_EN);

        CyDmaTdSetConfiguration(DMA_1_TD[1], TFR_CNT, DMA_1_TD[0],

        TD_INC_DST_ADR | TD_AUTO_EXEC_NEXT | TD_TERMOUT0_EN | DMA_1__TD_TERMOUT_EN);

        CyDmaTdSetAddress(DMA_1_TD[0], LO16((uint32)ADC_SAR_1_SAR_WRK0_PTR), LO16((uint32)&adc_buffer1[0]));

        CyDmaTdSetAddress(DMA_1_TD[1], LO16((uint32)ADC_SAR_1_SAR_WRK0_PTR), LO16((uint32)&adc_buffer2[0]));

        CyDmaChSetInitialTd(DMA_1_Chan, DMA_1_TD[0]);

        CyDmaChEnable(DMA_1_Chan, 1);

      }


       

      CY_ISR(ISR_DMA_DONE_ADC)

      {

        CyDmaChStatus(DMA_1_Chan, &currentTD, NULL);

       

        //process adc_buffer2

        if (currentTD == DMA_1_TD[0]) {

        LED_BLUE_DR |= LED_BLUE_MASK; //Turn on LED

        }

       

        //process adc_buffer1

        else if (currentTD == DMA_1_TD[1]) {

        LED_BLUE_DR &= ~LED_BLUE_MASK;  //Turn off LED


        }

        CyDmaClearPendingDrq(DMA_1_Chan); //ISR never gets called if this line is included

        • 1. Re: DMA interrupt repeatedly called
          BoTa_264741

          user_27...,

          Try to remove TD_AUTO_EXEC_NEXT qaualifier.

           

          • 2. Re: DMA interrupt repeatedly called
            LePo_1062026

            user_275561502,

             

            Your design intent is not clear from your description.

             

            This is my understanding of what you are asking.

            You intend to continuously bounce between adc_buffer1 and adc_buffer2 indefinitely.

             

            Your question deals with the ISR is called on every sample transferred(?).

             

            It appears you are using DMA_1__TD_TERMOUT_EN for TD[0] and TD[1].  If ISR_DMA_DONE_ADC is being generated from the 'nrq' output of DMA_1, then you should only call the ISR after 32 samples are transferred.  Now the ISR will continuously repeat since the end of TD[1] calls TD[0] to start everything over.   It sounds that you are looking for a terminating event.

             

            You need to determine the conditions of your terminating event.  Once you determine that, you can stop ADC_SAR_1.  This will stop the DMA.

             

            I'll try to help further but I will need more information.

             

            Len

             

            PS: user_342122993 suggestion about removing TD_AUTO_EXEC_NEXT makes sense if you want your terminating event for the DMA to be after TD[0]  or TD[1].  Note:  This will only stop the DMA not the ADC_SAR_1 conversions.