• AVR Freaks

Hot!PIC32MZ - DMA Stops working right with two DMA Channels

Author
Joe
New Member
  • Total Posts : 12
  • Reward points : 0
  • Joined: 2015/11/17 06:43:52
  • Location: 0
  • Status: offline
2017/02/26 06:21:48 (permalink)
0

PIC32MZ - DMA Stops working right with two DMA Channels

Hello Guys,
 
I am using a PIC32MZ2048ECG144 in a current project. 
I use two DMA channels. One to get data out of the SPI1 port and the other one to get a UART console.
 
If I use just one DMA channel at a time all works as expected.
But if I want to use both at the same time then channel 0 (SPI) gets stuck and stops working. Channel 1 (UART) operates just fine ...
 
Here is how I initialized both channels:
void dma_init(void)
{
    DMACONbits.ON = 0; //DMA module is disabled
    
//******************************************************************************
// DMA 0 für die Musterausgabe über SPI 1
//****************************************************************************** 
    
    DCH0CONbits.CHAEN = 0; //Channel is disabled on block transfer complete
    DCH0CONbits.CHPRI = 3; //Channel has priority 3 (highest)
    
// DCH0SSAbits.CHSSA = VirtToPhys((void*)&dma_muster[0]); //Source Address
    DCH0DSAbits.CHDSA = VirtToPhys((void*)&SPI1BUF); //Destination Address
    
    DCH0SSIZbits.CHSSIZ = 504; //Source Size Bytes
    DCH0DSIZbits.CHDSIZ = 4; //Destination Size Bytes
    DCH0CSIZbits.CHCSIZ = 4; //Cell Size - Übertragene Bytes pro transfer
    
    DCH0INTbits.CHCCIE = 1; //Channel Cell Transfer Complete Interrupt Enable bit
    DCH0INTbits.CHBCIE = 1; //Channel Block Done Interrupt Enable bit
        
    IPC33bits.DMA0IP = 6; // Set DMA 0 interrupt priority to 6
    IFS4bits.DMA0IF = 0; // Reset the DMA 0 interrupt flag
    IEC4bits.DMA0IE = 1; // Enable interrupts from DMA 0
    
    DCH0ECONbits.SIRQEN = 1; //Start channel cell transfer if an interrupt matching CHSIRQ occurs
    DCH0ECONbits.CHSIRQ = 111; //SPI1 Tx Interrupt will trigger a DMA transfer
    
    DCH0CONbits.CHEN = 1; //Channel is enabled 

//******************************************************************************
// DMA 1 für die Ausgabe über UART2
//****************************************************************************** 
    
    DCH1CONbits.CHAEN = 0; //Channel is disabled on block transfer complete
    DCH1CONbits.CHPRI = 2; //Channel has priority 2
    
    DCH1DSAbits.CHDSA = VirtToPhys((void*)&U2TXREG); //Destination Address
    
    DCH1DSIZbits.CHDSIZ = 1; //Destination Size Bytes
    DCH1CSIZbits.CHCSIZ = 1; //Cell Size - Übertragene Bytes pro transfer
    
    DCH1INTbits.CHCCIE = 1; //Channel Cell Transfer Complete Interrupt Enable bit
    DCH1INTbits.CHBCIE = 1; //Channel Block Done Interrupt Enable bit
        
    IPC33bits.DMA1IP = 4; // Set DMA 1 interrupt priority to 4
    IFS4bits.DMA1IF = 0; // Reset the DMA 1 interrupt flag
    IEC4bits.DMA1IE = 1; // Enable interrupts from DMA 1
    
    DCH1ECONbits.SIRQEN = 1; //Start channel cell transfer if an interrupt matching CHSIRQ occurs
    DCH1ECONbits.CHSIRQ = 147; //UART2 Tx Interrupt will trigger a DMA transfer
    
    DCH1CONbits.CHEN = 1; //Channel is enabled 
    
//****************************************************************************** 
    
    DMACONbits.ON = 1; //DMA module is enabled 
}

 
And here the Interrupt Handler:
//******************************************************************************
//DMA 0 Interrupt Block Transfer Complete
//****************************************************************************** 
#define antighostingdurchlaufe 100 //Erhöhen um Ghosting zu vermeiden!

void __ISR_AT_VECTOR(_DMA0_VECTOR, IPL6SRS) DMA0(void)
{
    if(DCH0INTbits.CHBCIF) //Wenn der Blocktransfer fertig ist
    {
//Do stuff here ...
    }
    IFS4bits.DMA0IF = 0; 
}

//******************************************************************************
//DMA 1 Interrupt Block Transfer Complete
//****************************************************************************** 
void __ISR_AT_VECTOR(_DMA1_VECTOR, IPL4SRS) DMA1(void)

    if(DCH1INTbits.CHBCIF) //Block ausgabe fertig
    {
        DCH1INTbits.CHBCIF = 0;
        DCH1CONbits.CHEN = 0;
    }
    
    DCH1INTbits.CHCCIF = 0;
    IFS4bits.DMA1IF = 0;
}

 
The UART transmission gets triggert here:
void UART2putString(unsigned char *String)
{
    while(DCH1CONbits.CHEN){} //Warten, bis das UART2 Modul frei ist
    
    DCH1SSAbits.CHSSA = VirtToPhys((void*)&String[0]); //Source Address
    DCH1SSIZbits.CHSSIZ = strlen(String); //Länge des String ermitteln und der Source Size zuordnen

    DCH1CONbits.CHEN = 1; //Channel Enable
    DCH1ECONbits.CFORCE = 1; //Force a DMA Transmit}
}

 
Would be nice if someone could help me :)
#1

13 Replies Related Threads

    timijk
    Super Member
    • Total Posts : 1216
    • Reward points : 0
    • Joined: 2007/11/26 00:30:07
    • Location: Taiwan
    • Status: offline
    Re: PIC32MZ - DMA Stops working right with two DMA Channels 2017/02/26 10:18:11 (permalink)
    0
    how do you start CH0?
     
    Another issue, in your dma_init(), you use "DCH1CONbits.CHEN = 1;" and in UART2putString(), 
    while(DCH1CONbits.CHEN){};

     
    does this cause any problem, how does it jump out of the while loop?
    #2
    Joe
    New Member
    • Total Posts : 12
    • Reward points : 0
    • Joined: 2015/11/17 06:43:52
    • Location: 0
    • Status: offline
    Re: PIC32MZ - DMA Stops working right with two DMA Channels 2017/02/26 10:42:07 (permalink)
    0
    Hello, 
     
    right, I forgot to post where Ch0 gets activated. This happens in a timer interrupt every 1,25ms here:
    void dma_ausgabe(unsigned int source_pointer)
    {
        DCH0SSAbits.CHSSA = VirtToPhys((void*)&dma_muster[source_pointer]); //Source Address
        
        DCH0CONbits.CHEN = 1; //Enable DMA Channel
        DCH0ECONbits.CFORCE = 1; //force a DMA Transmit
    }

     
    The part
    while(DCH1CONbits.CHEN){};

    was just for testing. The DCH1CONbits.CHEN bit gets set back to 0 if a block transfer is finished. So this should not be a problem.
     
    #3
    timijk
    Super Member
    • Total Posts : 1216
    • Reward points : 0
    • Joined: 2007/11/26 00:30:07
    • Location: Taiwan
    • Status: offline
    Re: PIC32MZ - DMA Stops working right with two DMA Channels 2017/02/26 18:25:28 (permalink)
    0
    I am not sure if this might be the cause.  In PIC32 C programming, if you use IFS4bits.DMA1IF = 0, it will read from TFS4 and update and write to TFS4.  The process is not atomic.
     
    It would be better to use CLR, SET, INV register to do it atomically, such as IFS4CLR = _IFS4_DMA1IF_MASK.  It will only alter the bits which is 1.
     

    12.2CLR, SET, and INV Registers
    Every I/O module register has a corresponding CLR (clear), SET (set) and INV (invert) register designed to provide fast atomic bit manipulations. As the name of the register implies, a value written to a SET, CLR or INV register effectively performs the implied operation, but only on the corresponding base register and only bits specified as ‘1’ are modified. Bits specified as ‘0’ are not modified.
    Reading SET, CLR and INV registers returns undefined values. To see the affects of a write operation to a SET, CLR or INV register, the base register must be read.

     
    In your case, if the DMA0IF is triggered when the "DMA0IFS4bits.DMA1IF = 0;" is executed, the DMA0IF might be overwritten.  So the ISR for DMA0 might not be triggered once for a while.
     
    I am not sure if the same situation could happen with your timer interrupt.
     
    Regarding the while loop, it seems you have some other process to initiate the block transfer.  Otherwise, how  you can get into the ISR to clear DCH1CONbits.CHEN to zero.
    #4
    Joe
    New Member
    • Total Posts : 12
    • Reward points : 0
    • Joined: 2015/11/17 06:43:52
    • Location: 0
    • Status: offline
    Re: PIC32MZ - DMA Stops working right with two DMA Channels 2017/02/27 04:51:27 (permalink)
    0
    I changed all SET and CLR operations to this: 
    IFS4CLR = _IFS4_DMA1IF_MASK 
    DCH1ECONSET = _DCH1ECON_CFORCE_MASK
     
    But it didn't change something.
     
    DMA Channel 1 gets started in UART2putString() here:
    DCH1CONbits.CHEN = 1; //Channel 1 enable
    DCH1ECONbits.CFORCE = 1; //Force a DMA Transmit
     
    Once a dma block transfer is completed, then the DCH1CONbits.CHEN bit automatically gets set back to 0;
    Because of the way I initialized it here in dma_init();
    DCH1CONbits-CHAEN = 0; //Channel is disabled on block transfer complete
     
    Or did I misunderstood something?
     
     
    post edited by Joe - 2017/02/27 04:56:27
    #5
    timijk
    Super Member
    • Total Posts : 1216
    • Reward points : 0
    • Joined: 2007/11/26 00:30:07
    • Location: Taiwan
    • Status: offline
    Re: PIC32MZ - DMA Stops working right with two DMA Channels 2017/02/27 05:20:39 (permalink)
    0
    not quite sure about what the problem is with SPI.
    channel 0 (SPI) gets stuck and stops working

    Do you mean the function dma_ausgabe() is called, but SPI DMA does not start?  Or the SPI DAM starts, but output is wrong?
     
    regarding the UART, I might be wrong, here is my understanding...
    void dma_init(void)
    {
    ...
    DCH1CONbits.CHEN = 1; //Channel is enabled <---- initially set to 1

    }
     
    void __ISR_AT_VECTOR(_DMA1_VECTOR, IPL4SRS) DMA1(void)
    {
    if(DCH1INTbits.CHBCIF) //Block ausgabe fertig  
    {
    DCH1INTbits.CHBCIF = 0;
    DCH1CONbits.CHEN = 0;   <----- you can only get here if DCH1ECONbits.CFORCE is set.
    }
    ...
    }

    void UART2putString(unsigned char *String)
    {
    while(DCH1CONbits.CHEN){}  //<----- you will hang here if DCH1CONbits.CHEN is 1.
    ...
    DCH1CONbits.CHEN = 1; //Channel Enable
    DCH1ECONbits.CFORCE = 1;
    }

    #6
    Joe
    New Member
    • Total Posts : 12
    • Reward points : 0
    • Joined: 2015/11/17 06:43:52
    • Location: 0
    • Status: offline
    Re: PIC32MZ - DMA Stops working right with two DMA Channels 2017/02/27 07:08:52 (permalink)
    0
    Do you mean the function dma_ausgabe() is called, but SPI DMA does not start? Or the SPI DAM starts, but output is wrong?

    Yes, dma_ausgabe() is called, but SPI DMA does not start. I checked this in debugging mode over the ICD3.
     
    The part with DCH1CONbits.CHEN is exactly the way you described it. It will wait on the while loop until DCH1CONbits.CHEN is 0 again. That happens when the complete blocktransfer is finished
     
    void dma_init(void)
    {
     ...
     DCH1CONbits.CHEN = 1; //Channel is enabled <---- initially set to 1
     
    }
     
    void __ISR_AT_VECTOR(_DMA1_VECTOR, IPL4SRS) DMA1(void)
    {
     if(DCH1INTbits.CHBCIF) //If a blocktransfer is finished
     {
     DCH1INTbits.CHBCIF = 0;
     DCH1CONbits.CHEN = 0; <----- you can only get here if DCH1ECONbits.CFORCE is set.
     }
     ...
    }

    void UART2putString(unsigned char *String)
    {
     while(DCH1CONbits.CHEN){} //<----- you will hang here if DCH1CONbits.CHEN is 1. <--- Yes, but if I hang here, a dma transfer on UART is still going
     ...
     DCH1CONbits.CHEN = 1; //Channel Enable
    DCH1ECONbits.CFORCE = 1;
    }

    You can ignore the part with while(DCH1CONbits.CHEN){} - I now commented it out and run the function  UART2putString("test\r") every second, so I don't have to worry that the transfer isn't complete. The Baudrate of the UART is set to 625k and just works fine.
    #7
    timijk
    Super Member
    • Total Posts : 1216
    • Reward points : 0
    • Joined: 2007/11/26 00:30:07
    • Location: Taiwan
    • Status: offline
    Re: PIC32MZ - DMA Stops working right with two DMA Channels 2017/02/27 08:29:45 (permalink)
    5 (1)
    I am not sure if the DMA does start but aborts because of some errors.  If you use SPI to send data, you will receive the data at the same time.  If you don't read the data from the buffer, there will be overrun error.
     
    http://www.microchip.com/forums/FindPost/657300
    #8
    cgiordan
    Super Member
    • Total Posts : 1364
    • Reward points : 0
    • Status: offline
    Re: PIC32MZ - DMA Stops working right with two DMA Channels 2017/02/27 08:40:24 (permalink)
    0
    timijk
    I am not sure if the DMA does start but aborts because of some errors.  If you use SPI to send data, you will receive the data at the same time.  If you don't read the data from the buffer, there will be overrun error.
     
    http://www.microchip.com/forums/FindPost/657300


    I was thinking the same thing...  Usually SPI acquires 2 channels for DMA for this very reason. 
    #9
    Joe
    New Member
    • Total Posts : 12
    • Reward points : 0
    • Joined: 2015/11/17 06:43:52
    • Location: 0
    • Status: offline
    Re: PIC32MZ - DMA Stops working right with two DMA Channels 2017/02/27 09:16:55 (permalink)
    0
    Even if I don't use the SDI pin?
     
    //****************************************************************************** 
    //SPI1CON
    //******************************************************************************
        SPI1CONbits.ON = 0; //SPI Deaktivieren

        SPI1CONbits.FRMEN = 0; //Framed SPI support is disabled
    // SPI1CONbits.FRMSYNC = //Framed SPI mode only
    // SPI1CONbits.FRMPOL = //Framed SPI mode only
        SPI1CONbits.MSSEN = 0; //Slave select SPI support is disabled
        SPI1CONbits.FRMSYPW = 0; //Frame sync pulse is one clock wide
    // SPI1CONbits.FRMCNT = //This bit is only valid in Framed mode
        SPI1CONbits.MCLKSEL = 0; //PBCLK2 is used by the Baud Rate Generator
    // SPI1CONbits.SPIFE = //Framed SPI mode only
    // SPI1CONbits.ENHBUF = //Enhanced Buffer mode is disabled
        SPI1CONbits.SIDL = 0; //Continue operation in Idle mode
        SPI1CONbits.DISSDO = 0; //SDO1 pin is controlled by the module
        SPI1CONbits.MODE32 = 1; //Communication 32Bit
        SPI1CONbits.MODE16 = 0; //When AUDEn = 0
        SPI1CONbits.SMP = 0; //Input data sampled at middle of data output time
        SPI1CONbits.CKE = 0; //0 Serial output data changes on transition from Idle clock state to active clock state (see CKP bit)
        SPI1CONbits.SSEN = 0; //SS1pin not used for Slave mode, pin controlled by port function
        SPI1CONbits.CKP = 1; //1 Idle state for clock is a high level; active state is a low level
        SPI1CONbits.MSTEN = 1; //Master mode
        SPI1CONbits.DISSDI = 1; //SDI pin is not used by the SPI module (pin is controlled by PORT function)
        SPI1CONbits.STXISEL = 1; //Interrupt is generated when the last transfer is shifted out of SPISR and transmit operations are complete
    // SPI1CONbits.SRXISEL = //Just if SDI is used
            
        
    IEC3bits.SPI1EIE = 0; //Turn off error detection Interrupt
        
        SPI1CONbits.ON = 1; //SPI Aktivieren

    #10
    cgiordan
    Super Member
    • Total Posts : 1364
    • Reward points : 0
    • Status: offline
    Re: PIC32MZ - DMA Stops working right with two DMA Channels 2017/02/28 04:58:38 (permalink)
    4 (1)
    I believe that disabling the SDI pin (via DISSDI bit) will only prevent the PIC32 hardware from "assigning" the designated SDIx pin for a SPIx module to the data input line.  The pin then will not be SPIx controlled have you.  Correct me if I am wrong, this does not disable the inherent nature of SPI performing a data exchange with the SPIxBUF shift register - even if the read data is bogus data on a transfer.  Either way, you can easily validate this when you notice the SPIx module freezes.  Look at the status register and observe if an overflow event has been captured.  If it has not, then there is another issue at hand.  
    #11
    timijk
    Super Member
    • Total Posts : 1216
    • Reward points : 0
    • Joined: 2007/11/26 00:30:07
    • Location: Taiwan
    • Status: offline
    Re: PIC32MZ - DMA Stops working right with two DMA Channels 2017/03/01 23:35:07 (permalink)
    0
    I tested it with PIC32MX250F128B and disabled SDI (DISSDI=1).  The SPIROV(receive overflow flag) will not be set if I keep on sending data out without reading from the SPIxBUF.
    #12
    Mohammed_Hassan
    Starting Member
    • Total Posts : 31
    • Reward points : 0
    • Joined: 2019/03/13 06:05:20
    • Location: 0
    • Status: offline
    Re: PIC32MZ - DMA Stops working right with two DMA Channels 2019/07/17 06:40:32 (permalink)
    0
    Is there any solution for this problem? 
    #13
    Joe
    New Member
    • Total Posts : 12
    • Reward points : 0
    • Joined: 2015/11/17 06:43:52
    • Location: 0
    • Status: offline
    Re: PIC32MZ - DMA Stops working right with two DMA Channels 2019/07/17 08:16:44 (permalink)
    0
    Didn‘t find any solution. Sadly I had to switch to a Cortex M4 and all worked fine.

    Do you have the same problem? How did you notice it?
    #14
    Jump to:
    © 2019 APG vNext Commercial Version 4.5