PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : ATXMega DMA Transaction Complete Interrupt kommt zu oft



Che Guevara
15.05.2014, 03:17
Hi,

ich möchte mit einem ATXMega192A3U die Werte eines ADC-Channels (ADCA.CH0) in ein Array ablegen, getriggert durch einen Timer (TCC1).
Der ADC ansich funktioniert, der Timer auch (wenn ich den OVF des Timers nutze).
Der Timer Period Wert ist auf 1000 gesetzt, das ergibt bei einem Prescaler = 1 einen (virtuellen) Timer-OVF alle 31.25us (bei 32MHz). TRFCNT ist auf 64 gesetzt, das sollte dann einen Transaction Complete Interrupt alle 2ms geben.
Leider hab ich wohl irgendwo einen Fehler drin, kann ihn aber nicht finden. Vielleicht fällt euch ja was auf:


void InitDmaCh3(void)
{
DMA.CH3.REPCNT = 0; //unlimited repeat
DMA.CH3.CTRLA = 0xA5; //CH enable, repeat enabled, singleshot enabled, 2byte burst
DMA.CH3.CTRLB = 0x01; //Channel Transaction Complete Lvl = Low
DMA.CH3.ADDRCTRL = 0x9D; //SAR=Burst,SAM=INC,DAR=Transaction,DAM=INC
DMA.CH3.TRIGSRC = 0x46; //TCC1 OVF
DMA.CH3.TRFCNT = 64; //******************************
DMA.CH3.SRCADDR0 = (((uint32_t)(&ADCA.CH0.RES))>>0*8) & 0xFF;
DMA.CH3.SRCADDR1 = (((uint32_t)(&ADCA.CH0.RES))>>1*8) & 0xFF;
DMA.CH3.SRCADDR2 = (((uint32_t)(&ADCA.CH0.RES))>>2*8) & 0xFF;
DMA.CH3.DESTADDR0 = (((uint32_t)(&AdcArray[0]))>>0*8) & 0xFF;
DMA.CH3.DESTADDR1 = (((uint32_t)(&AdcArray[0]))>>1*8) & 0xFF;
DMA.CH3.DESTADDR2 = (((uint32_t)(&AdcArray[0]))>>2*8) & 0xFF;
}

void InitAdcReglerTimer(void)
{
TCC1.CTRLA = 0x01; //Prescaler = 1
TCC1.CTRLB = 0x00; //Normal Mode
TCC1.INTCTRLA = 0x00; //No Interrupt
TCC1.PER = 1000; //31.25us (x 64 = 0.002)
}

ISR(DMA_CH3_vect)
{
DMA.CH3.CTRLB |= 0x10; //clear Interrupt flag

ReglerTimerCnt++;
if(ReglerTimerCnt>=250)
{
ReglerTimerCnt = 0;
SendPCUart("a",1);
}

TimeElapsed += 1;
TimerFlag = 1;

AdcValue= 0;
for(uint8_t i=0;i<64;i++)
{
AdcValue+= AdcArray[i];
}

}


Die SendPCUart-Routine schreibt ein "a" über die USART, das sollte eigentlich alle 0.002s * 250 (ReglerTimerCnt) = 0.5s erfolgen, kommt aber wesentlich öfter (wie oft genau kann ich nicht sagen, geschätzt wohl 500-5000 mal pro sekunde (ich weiß, ist keine wirkliche Angabe, aber es reicht, um sagen zu können, dass was falsch läuft).

Vielen Dank & Gruß
Chris

EDIT:
Hab jetzt den "Fehler" gefunden: Wenn der Interrupt des Timers nicht ausgeführt wird, triggert er andauernd den DMA, weil anscheinand das OVF-Bit nicht zurückgesetzt wird.
Gibts eventuell eine Möglichkeit, das zu umgehen? Ansonsten bringt mir der DMA in diesem Fall garnichts, mir gehts ja darum, den Interrupt des Timers zu umgehen.

EDIT2:
Hab jetzt die Lösung (eine sehr gute sogar):
Ich verwende das EventSystem als Trigger, dieses kann man mit einem Prescaler konfigurieren. Hab jetzt 1024 gewählt, damit stimmt das Timing zwar nicht 100%, aber die paar us sind nicht so schlimm. Außerdem hab ich jetzt wieder einen Timer frei.