ATxMega: DMA arbeitet nicht wie erwartet

Gast #4821635
Hallo,

ich möchte zwei DMA Kanäle (0/1) dazu benutzen, meinen DAC mit Daten zu 
versorgen, aber soweit kommt es noch gar nicht.

Meine Konfiguration sieht folgendermaßen aus:
1
PORTD_DIR = 0xFF;
2
  PORTB_DIR = 0xFF;
3
  PORTC_DIR = 0xFF;
4
  PORTC_OUT = 0;
5
  TCC1_CTRLA = TC_CLKSEL_DIV1_gc;
6
  TCC1_PERBUF = 256;
7
  //TCC1_INTCTRLA = 0x02;
8
  
9
  DMA.CH0.CTRLA = DMA_CH_SINGLE_bm | DMA_CH_BURSTLEN_2BYTE_gc;              //DMA Block macht bei jedem Trigger 2 Byte (signle)
10
  DMA.CH0.CTRLB = 0x03;                                  //Interrupt mit höchster Priorität
11
  DMA.CH0.ADDRCTRL = DMA_CH_SRCRELOAD_BLOCK_gc;                      //Nach jedem Block die Quelladresse reseten
12
  DMA.CH0.ADDRCTRL |= DMA_CH_DESTDIR_INC_gc;                        //Quelladresse immer +1
13
  DMA.CH0.ADDRCTRL |= DMA_CH_DESTRELOAD_BURST_gc;                      //Zieladresse nach jedem Burst (2Byte) neu laden
14
  DMA.CH0.ADDRCTRL |= DMA_CH_DESTDIR_FIXED_gc;                      //Zieladresse ist FIX
15
  DMA.CH0.TRIGSRC = DMA_CH_TRIGSRC_TCC1_OVF_gc;                      //Triggerevtn ist Timer TCC1 overflow
16
  DMA.CH0.TRFCNT = BUFFER_SIZE*2;                              //buffer_SIZE*2 Bytes
17
  DMA.CH0.REPCNT = 1;                                    //0 WIederholungen - nach 1 Block ist Transaction fertig
18
  DMA.CH0.SRCADDR0 = (DWORD)&DMA_Buffer1 & 0xFF;
19
  DMA.CH0.SRCADDR1 = ((DWORD)&DMA_Buffer1>>8) & 0xFF;
20
  DMA.CH0.SRCADDR2 = ((DWORD)&DMA_Buffer1>>16) & 0xFF;
21
  DMA.CH0.DESTADDR0 = (DWORD)&DACB.CH0DATA & 0xFF;
22
  DMA.CH0.DESTADDR1 = ((DWORD)&DACB.CH0DATA>>8) & 0xFF;
23
  DMA.CH0.DESTADDR2 = ((DWORD)&DACB.CH0DATA>>16) & 0xFF;
24
  
25
  DMA.CH1.CTRLA = DMA_CH_SINGLE_bm | DMA_CH_BURSTLEN_2BYTE_gc;              //DMA Block macht bei jedem Trigger 2 Byte (signle)
26
  DMA.CH1.CTRLB = 0x03;                                  //Interrupt mit höchster Priorität
27
  DMA.CH1.ADDRCTRL = DMA_CH_SRCRELOAD_BLOCK_gc;                      //Nach jedem Block die Quelladresse reseten
28
  DMA.CH1.ADDRCTRL |= DMA_CH_DESTDIR_INC_gc;                        //Quelladresse immer +1
29
  DMA.CH1.ADDRCTRL |= DMA_CH_DESTRELOAD_BURST_gc;                      //Zieladresse nach jedem Burst (2Byte) neu laden
30
  DMA.CH1.ADDRCTRL |= DMA_CH_DESTDIR_FIXED_gc;                      //Zieladresse ist FIX
31
  DMA.CH1.TRIGSRC = DMA_CH_TRIGSRC_TCC1_OVF_gc;                      //Triggerevtn ist Timer TCC1 overflow
32
  DMA.CH1.TRFCNT = BUFFER_SIZE*2;                              //buffer_SIZE*2 Bytes
33
  DMA.CH1.REPCNT = 1;                                    //0 WIederholungen - nach 1 Block ist Transaction fertig
34
  DMA.CH1.SRCADDR0 = (DWORD)&DMA_Buffer2 & 0xFF;
35
  DMA.CH1.SRCADDR1 = ((DWORD)&DMA_Buffer2>>8) & 0xFF;
36
  DMA.CH1.SRCADDR2 = ((DWORD)&DMA_Buffer2>>16) & 0xFF;
37
  DMA.CH1.DESTADDR0 = (DWORD)&DACB.CH0DATA & 0xFF;
38
  DMA.CH1.DESTADDR1 = ((DWORD)&DACB.CH0DATA>>8) & 0xFF;
39
  DMA.CH1.DESTADDR2 = ((DWORD)&DACB.CH0DATA>>16) & 0xFF;
40
  
41
  DMA.CTRL = DMA_ENABLE_bm | DMA_DBUFMODE_CH01_gc;
42
  DMA.CH0.CTRLA |= DMA_CH_ENABLE_bm;
43
    
44
  DACB.CTRLA = DAC_CH1EN_bm | DAC_CH0EN_bm | DAC_ENABLE_bm;                //Alle kanäle vom DAC aktivieren
45
  DACB.CTRLB = DAC_CHSEL_DUAL_gc;                              //Kanäle getrennt steuern
46
  DACB.CTRLC = DAC_REFSEL_AVCC_gc;                            //VCC als Referenzspannung

Zusätzlich ist das Interrupt definiert mit:
1
#define BUFFER_SIZE 256
2

3
WORD DMA_Buffer1[BUFFER_SIZE];
4
WORD DMA_Buffer2[BUFFER_SIZE];
5

6
ISR(DMA_CH0_vect){
7
  PORTC_OUTTGL = PIN6_bm;
8
  //reloadBuffer(DMA_Buffer1);
9
}
10

11

12
ISR(DMA_CH1_vect){
13
  PORTC_OUTTGL = PIN5_bm;
14
  DMA.CH0.CTRLA |= DMA_CH_ENABLE_bm;
15
  //reloadBuffer(DMA_Buffer2);
16
}

Es sollen also aus Buffer1 mit jedem Timerüberlauf zwei Bytes in den DAC 
geschrieben werden. Nach dem Block - ich möchte nur einen machen - soll 
der DMA.CH0 aktiviert werden - ping pong Modus. Der Timer macht jede 
256/14745600 Sekunden einen Überlauf - das macht ca. 57600 Überläufe pro 
Sekunde. 57600 / BUFFER_SIZE = 225. Ich erwarte also eigentlich eine 
Interruptfrequenz von 225Hz, nicht 114kHz.

Meine Beobachtung ist nun die folgende, dass der DMA.CH0 mit einer 
Frequenz von 114kHz ständig ein Interrupt schmeißt. CH1 wird nie 
aktiviert. Meine Parameter scheinen keinen Einfluss auf das Verhalten zu 
haben.

Habe ich ein Verdtänsnisproblem?

Vielen dank schonmal :)
Gast #4822170
Danke, das hat insofern etwas geholfen, dass der Interrupt jetzt mit 
einer Frequenz von 800Hz statt 114kHz springt. Er sollte aber mit ca. 
25Hz laufen.

Auch wenn ich die Triggerquelle, den Timer, DEUTLICH verlangsamer - 
esbleiben jetzt immernoch 800Hz.

Ich lösche das Interrupt Flag mit dem Schreiben einer 1:
1
ISR(DMA_CH0_vect){
2
  PORTC_OUTTGL = PIN6_bm;
3
  DMA.CH0.CTRLB |= (1<<4);
4
  DMA.CH1.CTRLA |= DMA_CH_ENABLE_bm;
5
  //reloadBuffer(DMA_Buffer1);
6
}
7

8

9
ISR(DMA_CH1_vect){
10
  PORTC_OUTTGL = PIN5_bm;
11
  DMA.CH1.CTRLB |= (1<<4);
12
  DMA.CH0.CTRLA |= DMA_CH_ENABLE_bm;
13
  //reloadBuffer(DMA_Buffer2);
14
}
#4822695
Hi,

damit deaktiviere ich den DMA Channel nachdem die Daten gesendet wurden.
Hast du geschaut ob ggf. das Errorbit gesetzt ist ?

In der ISR steht :
1
DMA_TX_CHANNEL.TRFCNT = 0;
2
DMA_TX_CHANNEL.CTRLA &= ~DMA_CH_ENABLE_bm;  // this shouldn't be necessary
3
DMA_TX_CHANNEL.CTRLB |= (DMA_CH_TRNIF_bm | DMA_CH_ERRIF_bm);

Ich lade aber die Adressen für Quelle und Ziel nicht nach. Du willst ja 
den ganzen Buffer senden, und bei jedem Timerüberlauf zwei Byte senden , 
oder ?

Ich sende bei mir immer den ganzen Inhalt des Arrays, aber bei dir 
sollte es auch gehen wenn du die Adressen nicht neu lädtst. Nur am Ende 
müsstest du den Buffer neu laden.

Hier meine Initialisierung, die Quelle weise ich bei mir erst kurz vor 
dem aufrufden zu. :
1
void DMA_TX_Raspi_Init()
2
{
3
  // reset source address
4
  DMA_TX_Raspi_CHANNEL.SRCADDR0 = 0;
5
  DMA_TX_Raspi_CHANNEL.SRCADDR1 = 0;
6
  DMA_TX_Raspi_CHANNEL.SRCADDR2 = 0;
7

8
  // set up destination address
9
  DMA_TX_Raspi_CHANNEL.DESTADDR0 = (((uint16_t) &USART_Netzwerk.DATA) >> 0) & 0xff;
10
  DMA_TX_Raspi_CHANNEL.DESTADDR1 = (((uint16_t) &USART_Netzwerk.DATA) >> 8) & 0xff;
11
  DMA_TX_Raspi_CHANNEL.DESTADDR2 = 0;
12

13
  DMA_TX_Raspi_CHANNEL.ADDRCTRL = DMA_CH_SRCRELOAD_NONE_gc;        // never reload source address
14
  DMA_TX_Raspi_CHANNEL.ADDRCTRL |= DMA_CH_SRCDIR_INC_gc;        // increment source address during transfer
15
  DMA_TX_Raspi_CHANNEL.ADDRCTRL |= DMA_CH_DESTRELOAD_NONE_gc;      // destination address does not need to be reloaded
16
  DMA_TX_Raspi_CHANNEL.ADDRCTRL |= DMA_CH_DESTDIR_FIXED_gc;        // the destination address should be fixed
17

18
  DMA_TX_Raspi_CHANNEL.TRIGSRC = DMA_CH_TRIGSRC_USARTF0_DRE_gc;      // automatically trigger a new burst when UARTF0 is ready
19
  DMA_TX_Raspi_CHANNEL.TRFCNT = 0;                    // reset block size
20
  DMA_TX_Raspi_CHANNEL.REPCNT = 0;                    // do not repeat block transfers
21
  DMA_TX_Raspi_CHANNEL.CTRLA = DMA_CH_SINGLE_bm;            // single shot mode (i.e. one burst transfer per trigger event)
22
  DMA_TX_Raspi_CHANNEL.CTRLA |= DMA_CH_BURSTLEN_1BYTE_gc;        // 1 byte bursts
23
  DMA_TX_Raspi_CHANNEL.CTRLB |= DMA_CH_TRNINTLVL_LO_gc;
24
}

Gruß JackFrost

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 9 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.