From Array to Timer with DMA

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

Hello, i want to copy one Byte at each Trigger from an Array to the Register TCD0.CCA
The Trigger is TCD0.CCB
But no Data is written to TCD0.CCA. I have inserted an Interrupt witch toggles an LED to test if the TCD0.CCB makes an Interrupt. This works.
Whats wrong?

#include 
#include 
uint8_t PWMArray[4];

int main(void)
{
    	
		
		PWMArray[0] = 10;

		//########Clock#################
    	//external 16MHz XTal
    	OSC_XOSCCTRL = OSC_XOSCSEL_XTAL_16KCLK_gc |	OSC_FRQRANGE_12TO16_gc;
    	OSC.CTRL |= OSC_XOSCEN_bm;
    	while(!(OSC.STATUS & OSC_XOSCRDY_bm));
    	CCP = CCP_IOREG_gc;
    	CLK.CTRL = CLK_SCLKSEL_XOSC_gc;
    	
    	OSC.PLLCTRL = OSC_PLLSRC_XOSC_gc | 0x02;
    	OSC.CTRL |= OSC_PLLEN_bm;
    	while (!(OSC.STATUS & OSC_PLLRDY_bm));  // wait until PLL stable
    	CCP = CCP_IOREG_gc;
    	CLK.CTRL = CLK_SCLKSEL_PLL_gc;
    	//########Clock End#############
		
		TCD0.CTRLA = TC_CLKSEL_DIV1_gc; 
		TCD0.CTRLB = 0b00010011; //Singleslope PWM 
		TCD0.PER = 400; 
		TCD0.CCA = 200; //13 = Code 0   22 = Code 1
		TCD0.CCB = 230;
		//TCD0.INTCTRLB = 0b00001100;
		PORTD.DIRSET = PIN0_bm;
		PORTD.DIRSET = PIN1_bm;
		// Interrupts on
		PMIC.CTRL |= PMIC_HILVLEN_bm;
		sei();

	   // -- DMA
	   DMA.CH0.DESTADDR0 = (( (uint16_t) &TCD0.CCA) >> 0) & 0xFF;
	   DMA.CH0.DESTADDR1 = (( (uint16_t) &TCD0.CCA) >> 8) & 0xFF;
	   DMA.CH0.DESTADDR2 = 0;
	   DMA.CH0.SRCADDR0 = (( (uint16_t) &PWMArray) >> 0) & 0xFF;
	   DMA.CH0.SRCADDR1 = (( (uint16_t) &PWMArray) >> 8) & 0xFF;
	   DMA.CH0.SRCADDR2 = 0;
	   DMA.CTRL = DMA_ENABLE_bm | DMA_DBUFMODE_DISABLED_gc | DMA_PRIMODE_RR0123_gc;    
	   DMA.CH0.CTRLA = DMA_CH_SINGLE_bm | DMA_CH_BURSTLEN_1BYTE_gc |DMA_CH_REPEAT_bm; 

	   DMA.CH0.ADDRCTRL =  DMA_CH_SRCDIR_FIXED_gc| DMA_CH_DESTDIR_FIXED_gc;
	   // Trigger Source
	   DMA.CH0.TRIGSRC = DMA_CH_TRIGSRC_TCD0_CCB_gc;
	   //DMA.CH0.TRFCNT = 1;	   
	   DMA.CH0.CTRLA |= DMA_CH_ENABLE_bm;
	   DMA.CH0.CTRLA |= DMA_CH_TRFREQ_bm;
	while(1)
    {

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

Try it in the simulator and give the results of that. Why are you using a manual DMA by using trfreq, since you want a timer to trigger it? Are you sure you want only 1 of the 2 timer bytes to be moved? You need to pick reload options.

It's always good to tell the toolchain, MCU and speed it's running at when posting.

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

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

Hello thanks for the help.
Its an XMega16A4 running at 32MHz, i use Atmel Studio 6.1. and an JTAGICE3
The manual start dont work. In TCD0.CCA is always the startvalue 200.
I want to move one Byte from an array into the timer.

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

Update:
when DMA writes to an variable instead of TCD0.CCA it works fine.
Why does DMA not write to TCD0.CCA??

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

Oh yeah...to use timers with DMA, you MUST setup/enable the correct timer ISR ( you can use NAKED to make it minimal ). :shock:

Side issue, does the code write CCP w/in 4 clks ( it may now but maybe not on another opt. setting ) ?

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

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

UPDATE:
The Trigger works fine. Now i made a little Step forward: the DMA can write to CCPH but not to CCPL and not to CCP!??

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

indianajones11 wrote:
Oh yeah...to use timers with DMA, you MUST setup/enable the correct timer ISR ( you can use NAKED to make it minimal ). :shock:

But in the XMega Datasheet i found this:

Quote:
If the interrupt flag related to the trigger source is cleared or the interrupt level enabled so that an interrupt is triggered,
the DMA request will be lost. Since a DMA request can clear the interrupt flag, interrupts can be lost

The trigger works without interrupts!

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

I think the Problem is writing the 16Bit Register. I have to write the H-Byte than the L-Byte. But DMA seems to send only one Byte even if i set a 2Byte Burst?!

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

ggerold wrote:
UPDATE:
The Trigger works fine. Now i made a little Step forward: the DMA can write to CCPH but not to CCPL and not to CCP!??
Do you mean CCA ..? Now it's triggering but not sending correct bytes? How'd you fix it so data got movin' ?

For the timer ISR, here's an example, it's not documented in the 'sheet, but even Atmel's A.N. code has to do this, for DMA/timer ( well the link below also uses the event system too, so may not apply if just using timer/DMA ) :

https://www.avrfreaks.net/index.p...

There are others who've posted the same workaround, and must be true for timer compare function just like OVF.

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

Last Edited: Sun. Apr 14, 2013 - 04:01 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
But DMA seems to send only one Byte even if i set a 2Byte Burst?!
You said you wanted only 1 byte sent. If > 1 byte then set trfcnt register = 2. You also need to increment SRC and DEST in addrctrl register.

I get it to work in the simulator using my sign #1 and #2 on a '256A3, at int. 2 MHz. It does work w/o making an ISR() also.

Quote:
The trigger works without interrupts!
Yes, I know it will TRIGGER w/o an ISR. But the ISR() makes the DMA actually trigger consistently, as it's how the interrupt flag's cleared per trigger, according to the OVF/CMP value. W/o it, the transaction will just finish ASAP, since the flag's always set after 1st trigger.

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

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

It seems that you must write both bytes to get it to work.

XMega A manual wrote:
3.11 Accessing 16-bits Registers
...
For a write operation, the low-byte of the 16-bit register must be written before the high-byte. The low-byte is then written into the temporary register. When the high-byte of the 16-bit register is written, the temporary register is copied into the low-byte of the 16-bit register in the same clock cycle.
It works for me on '128a1 if I make PWMArray 16 bit, set transfer count to 2 and increase source and destination address (and turn off repeat).

You can use this for the trigger ISR

EMPTY_INTERRUPT(TCD0_CCB_vect)

It will create a single reti.

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

Thanks to all,

both bytes must be written. The trigger didnt work right. Because the trigger don't clears the interrupt, he fires all the time. I didn't use the Interrupt but an Event to solve this.