DMA interrupt repeatedly called

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
josc_1234441
Level 1
Level 1
First like received

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 Solution
odissey1
Level 9
Level 9
First comment on KBA 1000 replies posted 750 replies posted

user_27...,

Try to remove TD_AUTO_EXEC_NEXT qaualifier.

View solution in original post

0 Likes
2 Replies
odissey1
Level 9
Level 9
First comment on KBA 1000 replies posted 750 replies posted

user_27...,

Try to remove TD_AUTO_EXEC_NEXT qaualifier.

0 Likes
Len_CONSULTRON
Level 9
Level 9
Beta tester 500 solutions authored 1000 replies posted

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.

Len
"Engineering is an Art. The Art of Compromise."
0 Likes