DMA ATXmega128a1

OP #2363592
Lesenswert?
• ▲
▼
Hallo,

ich möchte bei einem Atxmega128A1 einen Frequenzgenerator über den DMA 
laufen lassen. Hierzu soll der DMA bei jedem TCC0 Interrupt einen Wert 
an den Port (an welchem ein DAC angeschlossen ist) ausgeben. Das 
funktioniert auch soweit.
Jedoch ist mir aufgefallen, dass die Interruptserviceroutine den 
Prozessor beeinflusst. Wenn die die 3 Zeilen der ISR herrausnehme, kann 
man den Timer ändern wie man will, am die Zeit in der der DMA die Werte 
rausschickt ändert sich nicht.

Kann mir irgendwer weiterhelfen?

void init_TIMER_DMA (void)
{
  PMIC.CTRL=0x07;        //Enable all IRQs

  PORTA.DIR=0xff;

  EVSYS.CH0MUX=0xc0;      // Event0 = TCC0 OVFL
            // initialize TCC0 Counter
  TCC0.CTRLB=0x00;      // normal count
  TCC0.PER=40;        // top count value
  TCC0.CTRLA=0x00;      // counter stop

//Interrupt konfigurieren  (Highlevel Interrupt)
  TCC0.INTCTRLA = 0x03;


  //* initialize DMA chanel 0

  DMA.CTRL = DMA_CH_ENABLE_bm;
        // Aktivieren Single Buffer, Burst    Size 1Byte

        DMA.CH0.ADDRCTRL = DMA_CH_SRCRELOAD_TRANSACTION_gc | 
DMA_CH_SRCDIR_INC_gc | DMA_CH_DESTRELOAD_BURST_gc | 
DMA_CH_DESTDIR_INC_gc;

        DMA.CH0.TRIGSRC = 0x40;   //trigger source TCCo overflow
  DMA.CH0.DESTADDR0 =(uint8_t)(((uint16_t)&PORTA.OUT)>>0)&0xFF;
  DMA.CH0.DESTADDR1 =(uint8_t)(((uint16_t)&PORTA.OUT)>>8)&0xFF;
  DMA.CH0.DESTADDR2 =0;


  sei();
}


ISR(TCC0_OVF_vect)
{
}

void start_dma(void)
{
  DMA.CH0.TRFCNT = 256;
    DMA.CH0.SRCADDR0  =(uint8_t)(((uint16_t)&sinus)>>0) & 0xFF;
  DMA.CH0.SRCADDR1  =(uint8_t)(((uint16_t)&sinus)>>8) & 0xFF;
  DMA.CH0.SRCADDR2  =0;
    DMA.CH0.CTRLA = 0xA4;       // Aktivieren, Wiederholen, 1 Byte, 
Single
    TCC0.CTRLA=0x01;     // start counter
}
#2363767
Lesenswert?
• ▲
▼
Hallo,


> DMA.CH0.TRIGSRC = 0x40;   //trigger source TCC0 overflow

hier legst du fest, wann der DMA loslegen soll.

Die Interruptserviceroutine kann leer oder für andere Funktionen im 
Programm genützt werden. Nicht aber zum Starten der DMA-Routine. Sie 
wird hier gestartet: DMA.CH0.TRIGSRC = 0x40.

Mit dem Oszi oder einer Led kann man aber das zeitliche Verhalten der
Interruptserviceroutine testen.


Zum Beispiel:

PORTD.DIRTGL   |= PIN3_bm;  // Toggle Als Ausgang  festlegen


 ISR(TCC0_OVF_vect)
 {
  PORTD.OUTTGL |= PIN3_bm;  // Toggle am Ausgang
 }


Gruß xmega
OP #2364088
Lesenswert?
• ▲
▼
Das Problem ist, dass das Timer Overflow Flag nicht zurück gesetzt wird, 
wenn keine ISR gestartet wird. Somit läuft der DMA auf hochtouren. Am 
liebsten würde ich aber ganz auf die ISR verzichten, welchen Sinn hat 
sonst der DMA? dann könnte ich den Port auch in der ISR ansteuern.
Gast #2364427
Lesenswert?
• ▲
▼
Vielen Dank für die schnellen Antworten....
habe schon eine andere Lösung, ich nutze den DMA Channel 1 um über den 
selben Timer-EVENT das Interruptflag des Timer zurück zu setzen....so 
funktionierts, ohne reserven der CPU zu verschwenden.

Antwort schreiben

Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt. Bitte hier nur auf die ursprüngliche Frage antworten, für neue Fragen einen neuen Beitrag erstellen.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.