Hallo zusammen
Folgendes Problem:
Ich möchte gerne den ADC welcher sich im Freerunning-mode befindet
periodisch auslesen. Dies gerne mit dem DMA.
Der DMA soll Byte um Byte in einem Buffer schreiben.
Als "Takt" zum Schreiben soll der Overflow eines Timers (TCC1) dienen.
Mein Code sieht aktuell so aus:
1 | // set TCC1 to 11024Hz overflow, actually 11019.2838Hz (-0.052% error)
|
2 | TCC1.CTRLA = 0; // stop if running
|
3 | TCC1.CNT = 0;
|
4 | TCC1.PER = 1000-1;
|
5 |
|
6 | EVSYS.CH0MUX = EVSYS_CHMUX_TCC1_OVF_gc; // trigger on timer overflow
|
7 |
|
8 |
|
9 | // reset DMA controller
|
10 | DMA.CTRL = 0;
|
11 | DMA.CTRL = DMA_RESET_bm;
|
12 | while ((DMA.CTRL & DMA_RESET_bm) != 0);
|
13 |
|
14 | DMA.CTRL = DMA_CH_ENABLE_bm | DMA_DBUFMODE_CH01_gc; // double buffered with channels 0 and 1
|
15 |
|
16 | //Bei Double Buffering wird automatisch aus Channel 0 und 1 ein "Pair" gebildet.
|
17 | //Siehe dazu AVR1304.P8
|
18 |
|
19 | // channel 0
|
20 | // **** TODO: reset dma channels
|
21 | DMA.CH0.REPCNT = 1;
|
22 | DMA.CH0.CTRLA = DMA_CH_BURSTLEN_1BYTE_gc | DMA_CH_SINGLE_bm | DMA_CH_REPEAT_bm; // ADC result is 1 byte (8 bit word)
|
23 | DMA.CH0.CTRLB = 0x1;
|
24 | DMA.CH0.ADDRCTRL = DMA_CH_SRCRELOAD_BURST_gc | DMA_CH_SRCDIR_INC_gc | // reload source after every burst
|
25 | DMA_CH_DESTRELOAD_TRANSACTION_gc | DMA_CH_DESTDIR_INC_gc; // reload destination after every transaction
|
26 | DMA.CH0.TRIGSRC = DMA_CH_TRIGSRC_TCC1_OVF_gc; //DMA0 gets synched by TCC1
|
27 | DMA.CH0.TRFCNT = 32; // always the number of bytes, even if burst length > 1
|
28 | DMA.CH0.DESTADDR0 = (( (uint16_t) buffer_a) >> 0) & 0xFF;
|
29 | DMA.CH0.DESTADDR1 = (( (uint16_t) buffer_a) >> 8) & 0xFF;
|
30 | DMA.CH0.DESTADDR2 = 0;
|
31 | DMA.CH0.SRCADDR0 = (( (uint16_t) &ADCB.CH1.RES) >> 0) & 0xFF;
|
32 | DMA.CH0.SRCADDR1 = (( (uint16_t) &ADCB.CH1.RES) >> 8) & 0xFF;
|
33 | DMA.CH0.SRCADDR2 = 0;
|
34 |
|
35 | DMA.CH0.CTRLA |= DMA_CH_ENABLE_bm;
|
36 | //TCC1.INTCTRLA = 0x03;
|
37 | TCC1.CTRLA = TC_CLKSEL_DIV1_gc; // start timer, and in turn ADC
|
38 | }
|
39 | ...
|
40 | ISR(DMA_CH0_vect)
|
41 | {
|
42 |
|
43 | //Interrupt quittieren
|
44 | DMA.CH0.CTRLB |= 0x10;
|
45 | TCC1.INTFLAGS |= 0x01;
|
46 | PORTF.OUTTGL = 0x01
|
47 | }
|
ADC läuft. Dies wurde getestet.
Das Problem ist aktuell, dass der DMA Interrupt nicht nach TCC-Takt / 32
(wegen 32 Byte Datenlänge im DMA) kommt sondern eigentlich nach jedem
Byte. Wenn ich den TCC1 Prescaler bzw. dessen Periode reduziere =
schnellerer DMA Trigger, dann läuft gar nichts mehr.
Wäre froh, wenn jemand kurz über den Code schauen könnte.
Danke.
Gruss
Toubi