DMA chaining TD

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

cross mob
lock attach
Attachments are accessible only for community members.
greg79
Level 4
Level 4
25 replies posted 25 sign-ins 10 replies posted

I am trying to get samples from two LUTs with chained TDs. The clock signal starts TD0 (from LUT array to register, increase source address) which then starts TD1. Once TD1 is executed, an interrupt is generated to process the samples stored in the registers. For some reason the LED lights up but does not turn off and needless to say, there is no signal on the scope. What am I doing wrong? It has to be something to do with the TD configuration. Thank you for any help in advance.

td_chain.PNG

#define DMA_1_BYTES_PER_BURST 1
#define DMA_1_REQUEST_PER_BURST 1
#define DMA_1_SRC_BASE (CYDEV_SRAM_BASE)
#define DMA_1_DST_BASE (CYDEV_SRAM_BASE)

#include "project.h"
#include "LUT.h"

void configureDMA(void);
CY_ISR_PROTO(isr_1);

uint8_t sineReg;
uint8_t sawReg;

int main(void)
{
    CyGlobalIntEnable; /* Enable global interrupts. */
    configureDMA();
    VDAC8_1_Start();
    VDAC8_2_Start();
    isr_1_StartEx(isr_1);
    LED_pin_Write(0u);
    for(;;)
    {
    }
}
CY_ISR(isr_1){
    // do math on sample then write sit in DAC register 
    LED_pin_Write(1u);
    VDAC8_1_SetValue(sineReg);
    VDAC8_2_SetValue(sawReg);
    CyDelay(100);
    LED_pin_Write(0u);
}

void configureDMA(){

uint8 DMA_1_Chan;
uint8 DMA_1_TD[2];

/* DMA Configuration for DMA_1 */
DMA_1_Chan = DMA_1_DmaInitialize(DMA_1_BYTES_PER_BURST, DMA_1_REQUEST_PER_BURST, 
    HI16(DMA_1_SRC_BASE), HI16(DMA_1_DST_BASE));
DMA_1_TD[0] = CyDmaTdAllocate();
DMA_1_TD[1] = CyDmaTdAllocate();
CyDmaTdSetConfiguration(DMA_1_TD[0], 1, DMA_1_TD[1], CY_DMA_TD_INC_SRC_ADR | CY_DMA_TD_AUTO_EXEC_NEXT);
CyDmaTdSetConfiguration(DMA_1_TD[1], 1, DMA_1_TD[0], DMA_1__TD_TERMOUT_EN | CY_DMA_TD_INC_SRC_ADR);
CyDmaTdSetAddress(DMA_1_TD[0], LO16((uint32)sineWaveLUT), LO16((uint32)sineReg));
CyDmaTdSetAddress(DMA_1_TD[1], LO16((uint32)sawWaveLUT), LO16((uint32)sawReg));
CyDmaChSetInitialTd(DMA_1_Chan, DMA_1_TD[0]);
CyDmaChEnable(DMA_1_Chan, 1);
}

 

 

0 Likes
1 Solution
odissey1
Level 9
Level 9
First comment on KBA 1000 replies posted 750 replies posted

Greg,

There are multiple issues with code above. It appears that you want to use interrupt to update VDACs outputs. In such case, using DMA is totally unnecessary, it only slows down the process. Set VDACs values and increment table position directly in the isr.

P.S. 

If you want to use DMA updating VDACs outputs, then interrupt is unnecessary. Since you have 2 independent wave tables and 2 VDACs, I recommend to use 2 separate DMA to push the data. There are no timing advantages in using chained TDs. There is a risk to lose sync between the waves, but it is simple to implement (2 DMAs sharing one clock).

      When TDs are chained, the way they execute is: first TD1 pushes all data from Table1, and then passes chain to TD2, which now starts pushing all  data from Table2. I believe, this is not you wanted. You wanted one byte from Table1 pushed by TD1, and then one byte byte from Table2 pushed by TD2; and then Table address incremented and cycle repeated again. Unfortunately, chained TDs don't operate that way. 

     One way to make a synced output of multiple waves was proposed by <pavloven>:

synchronous multi-channel wavefrom generator with DACs and DMA ,

which uses an extra DMA to increment DMA pointer in the joint lookup table, by copying 4-byte data into some intermediate location in RAM, and then distributing each byte into own targets by another DMAs (or chained TDs, if you wish). This guarantees synchronicity, but in expense of the slower output rate.

DMA8x3_01a.png

View solution in original post

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

Greg,

There are multiple issues with code above. It appears that you want to use interrupt to update VDACs outputs. In such case, using DMA is totally unnecessary, it only slows down the process. Set VDACs values and increment table position directly in the isr.

P.S. 

If you want to use DMA updating VDACs outputs, then interrupt is unnecessary. Since you have 2 independent wave tables and 2 VDACs, I recommend to use 2 separate DMA to push the data. There are no timing advantages in using chained TDs. There is a risk to lose sync between the waves, but it is simple to implement (2 DMAs sharing one clock).

      When TDs are chained, the way they execute is: first TD1 pushes all data from Table1, and then passes chain to TD2, which now starts pushing all  data from Table2. I believe, this is not you wanted. You wanted one byte from Table1 pushed by TD1, and then one byte byte from Table2 pushed by TD2; and then Table address incremented and cycle repeated again. Unfortunately, chained TDs don't operate that way. 

     One way to make a synced output of multiple waves was proposed by <pavloven>:

synchronous multi-channel wavefrom generator with DACs and DMA ,

which uses an extra DMA to increment DMA pointer in the joint lookup table, by copying 4-byte data into some intermediate location in RAM, and then distributing each byte into own targets by another DMAs (or chained TDs, if you wish). This guarantees synchronicity, but in expense of the slower output rate.

DMA8x3_01a.png

lock attach
Attachments are accessible only for community members.

Greg,

attached is simple demo project showing synced output of 2 waves (sine and sawtooth) using a pair of VDAC8  and interrupt. Here both waves are stored in FLASH. Their values are written to the VDACs on interrupt. Output frequency = Clock_1 / TableSize (here = 256). The advantage of using interrupt is simplicity, the drawback is lower update rate (typically < 10-50kHz).

/odissey1

VDAC_isr_01a_A.pngVDAC_isr_01a_D.png

0 Likes