EDMA to DAC on E5

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hobby project time, I'm trying to DMA data from RAM to the DAC on an E5.

 

Everyone else who has done this seems to be using the EDMA in standard channel mode, rather than peripheral channel mode. If you need double buffering with that it used up all four EDMA channels, but at least it works.

 

In peripheral channel mode the EDMA copies data from RAM to the DAC's data register. It seems to work if you manually trigger it, but the problem is getting it to trigger from a timer. You have to set the EDMA trigger source to DACA in order to also set the destination address. In any case, there is no option to trigger from a timer or event. Problem is, it never triggers.

 

I set the DAC to use an event triggered by a timer. The events are being generated, I can run other stuff from them. I presume the DAC is triggering conversions from the events too, but it doesn't trigger the EDMA so the output is a constant value.

 

Has anyone made this work? How is it even supposed to work? Is it just broken?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Any luck here? I have very similar problems if not the same, described here:

https://www.avrfreaks.net/forum/e...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, I've hit the same snag.  Supposedly, when we trigger the DAC from a timer event, the DAC should trigger the EDMA to push another value to the DAC.  (In the E-series manual, figure 26-1 shows this as "EDMA request: data empty".)  When I try it, the timer overflow happens, but the EDMA transfer doesn't.  It works in standard mode, but not in peripheral mode.  Has anyone solved this?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I do not have a good command of English.
I apologize in advance that I may be misunderstanding the thread problem.

 

I use the following initialization code and there is no problem playing the wave file.
It uses EDMA's peripheral channel mode and burst transfer from RAM to DAC is triggered by timer overflow.

void play_init(void){

	// EVENTS
	EVSYS.CH0MUX = EVSYS_CHMUX_TCC4_OVF_gc;

	// DMA
	EDMA.CTRL = EDMA_ENABLE_bm | EDMA_PRIMODE_RR123_gc | EDMA_DBUFMODE_BUF23_gc;
	EDMA.CH2.TRIGSRC = EDMA_CH_TRIGSRC_DACA_CH0_gc;
	EDMA.CH2.ADDRCTRL = EDMA_CH_RELOAD_TRANSACTION_gc | EDMA_CH_DIR_INC_gc;
	EDMA.CH2.CTRLB = EDMA_CH_TRNINTLVL_MED_gc;
	EDMA.CH3.TRIGSRC = EDMA_CH_TRIGSRC_DACA_CH0_gc;
	EDMA.CH3.ADDRCTRL = EDMA_CH_RELOAD_TRANSACTION_gc | EDMA_CH_DIR_INC_gc;
	EDMA.CH3.CTRLB = EDMA_CH_TRNINTLVL_MED_gc;

	// DAC
	DACA.EVCTRL = DAC_EVSEL_0_gc;
	DACA.CTRLA = DAC_ENABLE_bm;
	DACA.CTRLB = DAC_CHSEL_SINGLE_gc;
	DACA.CTRLC = DAC_REFSEL_AREFA_gc | DAC_LEFTADJ_bm;
    DACA.CH0DATA = 0;
	ramp(1);
	DACA.CTRLA |= DAC_CH0EN_bm;
	DACA.CTRLB |= DAC_CH0TRIG_bm;
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks kabasan, I will give your method a try.

 

In the mean time I have this working using a normal channel, although I switched from using the DAC to using a timer and PWM: https://github.com/kuro68k/melod...

 

It sounds good.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Excellent!  I now have a 12-bit sine wave.  (My error was in setting bit 3 of DACA.EVCTRL.  Oops.)

At frequencies above 32kHz, I'm getting jitter because of the extra interrupt that the XMega-E requires to reset the EDMA after each transfer.  Lower frequencies look ok.

 

Code follows:

ISR(EDMA_CH0_vect)
{
	EDMA.CH0.CTRLB |= EDMA_CH_TRNIF_bm;   // clear INT flag    // EDMA.INTFLAGS = EDMA_CH0TRNFIF_bm;    // alternate flag location also works
	EDMA.CH0.CTRLA |= EDMA_CH_ENABLE_bm;   // re-enable EDMA Ch0 after trans complete
}

void GenerateArbWave12(int *data, uint8_t len)    
        // data[] contains a lookup table of length (len)
{
        ////////////////////////////////////////// Timer and Event config ​
	EVSYS.CH1MUX = 
		EVSYS_CHMUX_TCC4_OVF_gc;        // Event ch1 = tcc4 overflow
	TCC4.CTRLA = 
		TC_CLKSEL_DIV4_gc;		//  prescaler clk/4
	TCC4.INTCTRLA = 
		TC_OVFINTLVL_HI_gc;             //  enable interrupt
	TCC4.PER = F_CPU/len/freq/4 -1;  
	

        ////////////////////////////////////////// DAC config
	DACA.CTRLB = 
		DAC_CHSEL_SINGLE1_gc |          // DAC ch1 is active
		DAC_CH1TRIG_bm;			// DAC ch1 auto triggered by an event (CH1)
	DACA.CTRLC = 
		DAC_REFSEL_AVCC_gc;             // Use AVCC (3.3v), right adj
	DACA.EVCTRL = 
		DAC_EVSEL_1_gc;                 // Event Ch1 triggers the DAC conversion
	DACA.CTRLA = DAC_CH1EN_bm | DAC_ENABLE_bm;  // enable DACA channel 1
	
	
        ////////////////////////////////////////////  EDMA config
        EDMA.CTRL = EDMA_RESET_bm;
	EDMA.CH0.CTRLA = EDMA_CH_RESET_bm;
	EDMA.CH0.ADDRCTRL = 
		EDMA_CH_RELOAD_TRANSACTION_gc |   // Reload after transaction
		EDMA_CH_DIR_INC_gc;		  // increment source address
	EDMA.CH0.TRIGSRC = 
		EDMA_CH_TRIGSRC_DACA_CH1_gc;	  // DACA Ch1 is trigger source
	EDMA.CH0.TRFCNT = len*2;                  // data array has len values 
	EDMA.CH0.ADDR = (uint16_t)data;           // this is the source SRAM address
	EDMA.CH0.CTRLA = 
		EDMA_CH_ENABLE_bm |               //   enable EDMA Ch0
		EDMA_CH_SINGLE_bm |               //   one burst per trigger
		EDMA_CH_BURSTLEN_bm;              //   2 bytes per burst
	EDMA.CH0.CTRLB = 
		EDMA_CH_TRNIF_bm |                //  Clear flag
		EDMA_CH_TRNINTLVL_HI_gc;          // For XMegaE5, this ISR is necessary to re-enable channel after transaction
	EDMA.CTRL = EDMA_ENABLE_bm; 	          // Enable, single buffer, round robin



	PMIC.CTRL = PMIC_HILVLEN_bm;		  //  enable interrupts
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you use the double buffer mode, I think that stable operation can be performed even at 32 KHz or more.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My code does 32kHz (via 250kHz PWM rather than DAC, but same timing) audio without any jitter using double buffering.