ASF XMEGA [DMA => DAC] Continous transfer? No manual retrigger!

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

I'm trying to load the DAC of my xmaga using the DMA controller. For some reason the re-triggering the transaction is too slow and the waveform has a short flat spot at the begining of the sample.

 

The dma is triggered by timer overflow, the dma_transaction_done interrupt retriggers the DMA.

 

I want to set up the DMA so there is no need to retrigger it after every cycle. How do I do that?

Thanks!

 

PS: See scope drawing below!

 

 

#define SPEAKER_DAC              DACB
#define SPEAKER_DAC_CHANNEL      DAC_CH0
#define RATE_OF_CONVERSION       20000

#define NR_OF_SAMPLES            256

#define DMA_CHANNEL     0 

#define LED 	IOPORT_CREATE_PIN(PORTQ, 3)

#include <asf.h>

uint16_t  sine_wave[256] = {
	0x800,0x832,0x864,0x896,0x8c8,0x8fa,0x92c,0x95e,
	0x98f,0x9c0,0x9f1,0xa22,0xa52,0xa82,0xab1,0xae0,
	0xb0f,0xb3d,0xb6b,0xb98,0xbc5,0xbf1,0xc1c,0xc47,
	0xc71,0xc9a,0xcc3,0xceb,0xd12,0xd39,0xd5f,0xd83,
	0xda7,0xdca,0xded,0xe0e,0xe2e,0xe4e,0xe6c,0xe8a,
	0xea6,0xec1,0xedc,0xef5,0xf0d,0xf24,0xf3a,0xf4f,
	0xf63,0xf76,0xf87,0xf98,0xfa7,0xfb5,0xfc2,0xfcd,
	0xfd8,0xfe1,0xfe9,0xff0,0xff5,0xff9,0xffd,0xffe,
	0xfff,0xffe,0xffd,0xff9,0xff5,0xff0,0xfe9,0xfe1,
	0xfd8,0xfcd,0xfc2,0xfb5,0xfa7,0xf98,0xf87,0xf76,
	0xf63,0xf4f,0xf3a,0xf24,0xf0d,0xef5,0xedc,0xec1,
	0xea6,0xe8a,0xe6c,0xe4e,0xe2e,0xe0e,0xded,0xdca,
	0xda7,0xd83,0xd5f,0xd39,0xd12,0xceb,0xcc3,0xc9a,
	0xc71,0xc47,0xc1c,0xbf1,0xbc5,0xb98,0xb6b,0xb3d,
	0xb0f,0xae0,0xab1,0xa82,0xa52,0xa22,0x9f1,0x9c0,
	0x98f,0x95e,0x92c,0x8fa,0x8c8,0x896,0x864,0x832,
	0x800,0x7cd,0x79b,0x769,0x737,0x705,0x6d3,0x6a1,
	0x670,0x63f,0x60e,0x5dd,0x5ad,0x57d,0x54e,0x51f,
	0x4f0,0x4c2,0x494,0x467,0x43a,0x40e,0x3e3,0x3b8,
	0x38e,0x365,0x33c,0x314,0x2ed,0x2c6,0x2a0,0x27c,
	0x258,0x235,0x212,0x1f1,0x1d1,0x1b1,0x193,0x175,
	0x159,0x13e,0x123,0x10a,0xf2,0xdb,0xc5,0xb0,
	0x9c,0x89,0x78,0x67,0x58,0x4a,0x3d,0x32,
	0x27,0x1e,0x16,0xf,0xa,0x6,0x2,0x1,
	0x0,0x1,0x2,0x6,0xa,0xf,0x16,0x1e,
	0x27,0x32,0x3d,0x4a,0x58,0x67,0x78,0x89,
	0x9c,0xb0,0xc5,0xdb,0xf2,0x10a,0x123,0x13e,
	0x159,0x175,0x193,0x1b1,0x1d1,0x1f1,0x212,0x235,
	0x258,0x27c,0x2a0,0x2c6,0x2ed,0x314,0x33c,0x365,
	0x38e,0x3b8,0x3e3,0x40e,0x43a,0x467,0x494,0x4c2,
	0x4f0,0x51f,0x54e,0x57d,0x5ad,0x5dd,0x60e,0x63f,
	0x670,0x6a1,0x6d3,0x705,0x737,0x769,0x79b,0x7cd
};

void tc_init(void)
{
	tc_enable(&TCC0);
	tc_set_wgm(&TCC0, TC_WG_NORMAL);
	tc_write_period(&TCC0, (sysclk_get_per_hz() / RATE_OF_CONVERSION) - 1);

	tc_write_clock_source(&TCC0, TC_CLKSEL_DIV1_gc);
}

void dac_init(void)
{
	struct dac_config conf;
	dac_read_configuration(&SPEAKER_DAC, &conf);
	dac_set_conversion_parameters(&conf, DAC_REF_BANDGAP, DAC_ADJ_RIGHT);
	dac_set_active_channel(&conf, SPEAKER_DAC_CHANNEL, 0);
	//dac_set_conversion_trigger(&conf, SPEAKER_DAC_CHANNEL, 3);
	#ifdef XMEGA_DAC_VERSION_1
	dac_set_conversion_interval(&conf, 1);
	#endif

	dac_write_configuration(&SPEAKER_DAC, &conf);
	dac_enable(&SPEAKER_DAC);
}

void dma_transfer_done(){

 	dma_channel_enable(DMA_CHANNEL);
  	dma_channel_trigger_block_transfer(DMA_CHANNEL);

	ioport_toggle_pin(LED);

}

static void dma_init(void)
{	

	struct dma_channel_config config;

	memset(&config, 0, sizeof(config));

	dma_channel_set_burst_length(&config, DMA_CH_BURSTLEN_2BYTE_gc);
	dma_channel_set_transfer_count(&config, NR_OF_SAMPLES*2);

	dma_channel_set_src_reload_mode(&config, DMA_CH_SRCRELOAD_TRANSACTION_gc);
	dma_channel_set_dest_reload_mode(&config, DMA_CH_DESTRELOAD_BURST_gc);

	dma_channel_set_src_dir_mode(&config, DMA_CH_SRCDIR_INC_gc);
	dma_channel_set_dest_dir_mode(&config, DMA_CH_DESTDIR_INC_gc);

	dma_channel_set_source_address(&config, (uint16_t)(uintptr_t)sine_wave);
    dma_channel_set_destination_address(&config, (uint16_t)(uintptr_t)&DACB.CH0DATA);

	dma_channel_set_trigger_source(&config, DMA_CH_TRIGSRC_TCC0_OVF_gc);

	dma_channel_set_single_shot(&config);

	dma_enable();

	dma_set_callback(DMA_CHANNEL, dma_transfer_done);
	dma_channel_set_interrupt_level(&config, DMA_INT_LVL_HI);

	dma_channel_write_config(DMA_CHANNEL, &config);

	/* Use the configuration above by enabling the DMA channel in use. */
	dma_channel_enable(DMA_CHANNEL);
}

int main(void){

	ioport_set_pin_dir(LED, IOPORT_DIR_OUTPUT);
	ioport_set_pin_high(LED);

	pmic_init();
	board_init();
	sysclk_init();
	sleepmgr_init();

	tc_init();

	delay_init(32000000UL);
	dac_init();
	dma_init();

	cpu_irq_enable();

	while (true) {

	}

}

 

Attachment(s): 

Last Edited: Sat. Apr 28, 2018 - 05:29 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You need to use double buffering mode which alternately uses two DMA channels.

 

 

 

 

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

Thanks, I think that just did the trick, but I have to do more testing...

 

If I want to use two DAC outputs that will require all 4 channels of the DMA right?

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

Yes.
If you want to use two DACs, DMA requires 4 channels.

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

Couldn't it be done with one chanel and "repeat"?

 

 

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

I'm not sure how I could set repeats to infinite?! frown

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

I have no xmega, just had a look to the datasheet:

 

DMA Block mode and Repeat on ATxmega

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

What part, by the way? The E5 range has slightly different DMA.

 

Also: https://github.com/kuro68k/melod...