Hallo,
ich möchte mittels DMA - ausgelöst von einem Timer Interrupt - die an
PORTB anliegenden Bits in einen Buffer schreiben. Nach jeweils vier
Interrupts soll der Buffer ausgelesen werden, um mit den gespeicherten
Werten zu rechnen.
Das Datenblatt zum Thema DMA habe ich gelesen und auch schon einiges
ausprobiert. Es scheitert aber wohl noch an einigen grundlegenden
Verständnisproblemen.
Zunächst erstelle ich mir meinen Buffer und bestimme die Start- und
Zieladresse für meine DMA-Transfer:
1 | unsigned int sourceAddr;
|
2 | unsigned int destinationAddr;
|
3 |
|
4 | unsigned int buffer[6];
|
5 |
|
6 | sourceAddr = (unsigned int) &PORTB & 0x1FFFFFFF; // Physical address of PORTB
|
7 | destinationAddr = (unsigned int) &buffer & 0x1FFFFFFF; // Physical address of buffer
|
8 |
|
9 | DCH0SSA = sourceAddr; // source start address
|
10 | DCH0DSA = destinationAddr; // destination start address
|
Die "Source Size" sowie die "Cell Size" setze ich auf 2 byte (16bit von
PORTB), die Destination Size auf 8 byte. So müsste ein Block Transfer
nach den gewünschten vier Interrupts abgeschlossen sein und das
entsprechende Interrupt ausgelöst werden.
1 | DCH0SSIZ = 2; // DMA Channel 0 Source Size Register: 2 byte
|
2 | DCH0DSIZ = 8; // DMA Channel 0 Destination Size Register: 8 byte
|
3 | DCH0CSIZ = 2; // DMA Channel 0 Cell Size Register: 2 byte
|
Außerdem stelle ich ein, dass der Cell Transfer vom Timer 2 Interrupt
ausgelöst wird, ich aktiviere das Interrupt für einen abgeschlossenen
Block Transfer und schalte mein DMA-Modul dauerhaft ein:
1 | DCRCCON = 0; // CRC off
|
2 |
|
3 | DCH0ECONbits.CHSIRQ = 9; // Channel Transfer Start IRQ bits --> TMR2
|
4 | DCH0ECONbits.SIRQEN = 1; // Start channel cell transfer if an interrupt matching CHSIRQ occurs
|
5 |
|
6 | DCH0INTbits.CHBCIE = 0;
|
7 | DCH0INTbits.CHBCIF = 0;
|
8 | DCH0INTbits.CHBCIE = 1; // Channel Block Transfer Complete Interrupt Enable
|
9 |
|
10 | DCH0CONbits.CHAEN = 1; // Channel Automatic Enable bit
|
11 | DCH0CONbits.CHEN = 1; // Channel enabled
|
12 |
|
13 | DMACONbits.ON = 1; // DMA on
|
Timer 2 wird an anderer Stelle initialisiert und ich habe getestet, dass
die ISR ausgelöst wird. In jedem Interrupt "zähle ich mit", um dann im
vierten Interrupt - nachdem das "Channel Block Transfer Complete
Interrupt Flag" gesetzt ist - den Buffer auszulesen.
Da das Flag aber nie gesetzt wird, scheine ich hier noch irgendetwas
grundlegend falsch zu machen. Ich weiß, es ist ein sehr langer Post
geworden, aber vllt. findet ja jemand den Fehler. Würde mir wirklich
sehr weiterhelfen.. insofern schonmal vielen Dank für die
Unterstützung!!