- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
}
Solved! Go to Solution.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
user_27...,
something like that (DMA1 is the instance name of the DMA component)
// Variable declarations for DMA2
// uint8_t DMA_Chan;
// uint8_t DMA_TD[2];
...
CyDmaTdSetConfiguration(DMA_TD[0], TRANSFER_COUNT1, DMA_TD[1], TD_INC_DST_ADR | DMA1__TD_TERMOUT_EN);
CyDmaTdSetConfiguration(DMA_TD[1], TRANSFER_COUNT2, DMA_TD[0], TD_INC_DST_ADR | DMA1__TD_TERMOUT_EN);
/odissey1
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
user_27...,
Did you test the original code from the AN52705 ex. #5? Please explain how would you like to modify it.
/odissey1
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
if I understand AN52705 correct, there's no need to use two DMAs. According to table 1, DMA completion event can be set for a transaction descriptor. So, each TD will trigger the IRQ when this flag is set this on both TDs.
Regards
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Do you know how to set the DMA completion event for a TD? In the API there doesn't appear to be a specific flag for this. I just see:
TD_TERMOUT0_EN
TD_TERMOUT1_EN
DMA__TD_TERMOUT_EN
Should all of these flags be used? e.g.
CyDmaTdSetConfiguration(DMA_1_TD[0], TFR_CNT, DMA_1_TD[1],
TD_INC_DST_ADR | TD_AUTO_EXEC_NEXT | DMA_1__TD_TERMOUT_EN | 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 | DMA_1__TD_TERMOUT_EN | TD_TERMOUT1_EN | TD_TERMOUT0_EN);
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
user_27...,
something like that (DMA1 is the instance name of the DMA component)
// Variable declarations for DMA2
// uint8_t DMA_Chan;
// uint8_t DMA_TD[2];
...
CyDmaTdSetConfiguration(DMA_TD[0], TRANSFER_COUNT1, DMA_TD[1], TD_INC_DST_ADR | DMA1__TD_TERMOUT_EN);
CyDmaTdSetConfiguration(DMA_TD[1], TRANSFER_COUNT2, DMA_TD[0], TD_INC_DST_ADR | DMA1__TD_TERMOUT_EN);
/odissey1