4 Replies Latest reply on Apr 1, 2019 10:25 AM by BoTa_264741

    How to implement DMA ping pong buffering with two interrupts

    josc_1234441

      In the application note AN52705, Example 5 shows how two separate buffers can be used. I would like to implemented a ping-pong DMA for the SAR ADC but with an interrupt after each buffer is full. i.e. An ISR should be generated when Destination 1 is full and when Destination 2 is full.

      Is it correct to assume 2 DMAs are needed? If so how would these be configured so that one triggers the next?

       

      UPDATE: I have it working with the following flag settings: I would  now like to know if Dma_1_TD[0] or Dma_1_TD[1] triggered the ISR? i.e. is adc_buffer1 or adc_buffer2 full.

       

      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);
      

       

       

      #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};
      
      
      
      
      void init_adc_dma(void) {
      
        //Init DMA channel
        DMA_1_Chan = DMA_1_DmaInitialize(DMA_BYTES_PER_BURST, DMA_REQUEST_PER_BURST, HI16(DMA_SRC_BASE), HI16(DMA_DST_BASE));
        
        //Create TD instances
        DMA_1_TD[0] = CyDmaTdAllocate();
        DMA_1_TD[1] = CyDmaTdAllocate();
        
        //Configure each TD
        CyDmaTdSetConfiguration(DMA_1_TD[0], TFR_CNT, DMA_1_TD[1], 
        TD_INC_DST_ADR | TD_AUTO_EXEC_NEXT | TD_TERMOUT1_EN | TD_TERMOUT0_EN);
        CyDmaTdSetConfiguration(DMA_1_TD[1], TFR_CNT, DMA_1_TD[0], 
        TD_INC_DST_ADR | TD_AUTO_EXEC_NEXT | TD_TERMOUT1_EN | TD_TERMOUT0_EN); 
        
        //Set TD source and destination address
        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]));
        
        //Set the channel's initial TD
        CyDmaChSetInitialTd(DMA_1_Chan, DMA_1_TD[0]);
        
        //Enable the DMA channel
        CyDmaChEnable(DMA_1_Chan, 1);
      
      
      }
      
      
      /*
       *Called when the adc_buffer1 or adc_buffer2 is full
       */
      CY_ISR(ISR_DMA_DONE_ADC)
      {
        //Toggle LED
        LED_BLUE_DR ^= LED_BLUE_MASK;
        CyDmaClearPendingDrq(DMA_1_Chan);
        //Process the buffer
      }