Forum: Mikrocontroller und Digitale Elektronik Verständnisproblem DMA auf PIC32


von creo0612 (Gast)


Lesenswert?

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!!

von X4U (Gast)


Lesenswert?

leider habe ich auch keine Antwort, aber als Pic32 Nutzer empfehle ich 
das Microchip Forum.

von Gästchen (Gast)


Lesenswert?

Hallo,

welches Flag wird nie gesetzt?
Das des DMA-Interrupts, oder das vom Timer?

Den DMA-Interrupt hast du jedenfalls nicht aktiviert.

DMA ist oft schwierig. Zum Debuggen empfehle ich, das Ganze zu stoppen, 
und mal zu kucken, auf welchem Pointer der DMA steht. Ist er 
losgelaufen? Hat er einen Fehler (Es gibt ein Statusregister für diesen 
Zweck) und so weiter.

Anbei ein lauffähiges Beispiel für PIC32:
[c]
#include <sys/kmem.h>
/*DMA Transfer of Audio Data*/
void I2S_DMA_Transfer(uint16_t *buffer, uint16_t buffersize, bool 
abort){
    if(!abort){
        //switch dma module on
        DMACON = 0x0000;
        DMACONbits.ON = 1;      //switch DMA-Controller on

        //Channel 0 : data from playback  buffer to SPI
        DCH0SSA = DCH0DSA = DCH0SSIZ = DCH0DSIZ= 0;
        DCH0SSA = KVA_TO_PA((void*)buffer);    //source is playback 
buffer
        DCH0DSA = KVA_TO_PA((void*)&SPI1BUF);  //source is SPI
        DCH0SSIZ = buffersize;  //set source buffer size : buffersize
        DCH0DSIZ = 2;           //destination buffer size = 2;
        DCH0CSIZ = 2;           //channel size = 2BYte

        //setup channel 0
        DCH0CON = 0;            //Off, Priority 0
        DCH0CONbits.CHAEN = 1;  //Channel is always active
        DCH0ECON = 0;
        //set DMA to act on SPI TX IRQ
        DCH0ECONbits.SIRQEN = 1;
        DCH0ECONbits.CHSIRQ = 37;   //start IRQ = SPI TX done IF
        DCH0INT = DCH1INT= 0;
        DCH0INTbits.CHSHIE = 1; //buffer half transferred
        DCH0INTbits.CHSDIE = 1; //buffer tranfer complete


        //enable DMA Interrupt sources
        IFS2bits.DMA0IF = 0;
        IPC10bits.DMA0IP = 2;
        IEC2bits.DMA0IE = 1;

        //Kick off Transfer
        DCH0CONbits.CHEN = 1;
        IFS1bits.SPI1TXIF =0; IFS1bits.SPI1RXIF = 0;
        SPI1STATbits.SPIROV = 0;
        DCH0ECONbits.CFORCE = 1;
    }
    else{
        //Shut off DMA
        SPI1CONbits.ON = 0;
        DCH0CONbits.CHEN = DCH1CONbits.CHEN = 0;
        DMACONbits.ON = 0;
        IFS2bits.DMA0IF = 0;
        IEC2bits.DMA0IE = 0;
        //also, clear pending flags
        gINT.bits.DMA0_Halfway = 0;
        gINT.bits.DMA0 = 0;
    }
}
[\c]

von SchlumpfMops (Gast)


Lesenswert?

>sourceAddr = (unsigned int) &PORTB & 0x1FFFFFFF;        // Physical address of 
PORTB


Ist 'PORTB' nicht schon eine Adresse?
Wenn ja, warum dann &PORTB?
Warum die &0x1FFF..FF?

>um dann im
>vierten Interrupt - nachdem das "Channel Block Transfer Complete
>Interrupt Flag" gesetzt ist - den Buffer auszulesen.

Warum dann überhaupt DMA? Scheint mir mehr als sinnlos.

Gibt es beim PIC32 keinen "DMA-Complete" Interrupt?

von Gästchen (Gast)


Lesenswert?

SchlumpfMops schrieb:
>>sourceAddr = (unsigned int) &PORTB & 0x1FFFFFFF;        // Physical address of
> PORTB
>
>
> Ist 'PORTB' nicht schon eine Adresse?
> Wenn ja, warum dann &PORTB?
> Warum die &0x1FFF..FF?

&PORTB ist die Adresse des PORTB Registers, das passt schon so. Das 
0x1FF... ist die Transformation in phyiskalische Adressen, welche ich in 
meinem Beispiel mit KVA_TO_PA() mache.
Kuckt man in den Header:

#define KVA_TO_PA(v)   ((_paddr_t)(v) & 0x1fffffff)

...sollte also passen, Microchip machts genaus.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.