DMA ATXmega128a1

OP #2363592
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
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
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
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

Eine eigene Frage? Dieser Thread ist über 15 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

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.