• AVR Freaks

Hot!Chaining DMA?

Author
Wavelength
Super Member
  • Total Posts : 312
  • Reward points : 0
  • Joined: 2012/08/13 08:33:08
  • Location: Cincinnati, Ohio USA
  • Status: offline
2021/01/06 07:59:20 (permalink)
4 (1)

Chaining DMA?

All,
I have a new project I am considering that requires 24 bits output over DMA. So the idea I had was to use a 64pin QFN part and have PORTB setup as a 16bit output and then use an 8 bit PMP and chain two DMA together like this:
 
a) Set a timer up for the output rate.
b) DMA0 triggers loads PORTB with the most significant 16 bits of the 24 bits.
c) Chain DMA0 to DMA1 to send the remaining 8 bits out the PMP
d) Use the WR- to latch all 24 bits using 3 74LVC573 octal latches to latch the 24bits into service.
 
Considering either the PIC32MX470 or the PIC32MZ-EF depending on other interrupt and foreground processing required.
 
Thoughts? Better way to do this?
 
Thanks,
Gordon
#1

12 Replies Related Threads

    Wavelength
    Super Member
    • Total Posts : 312
    • Reward points : 0
    • Joined: 2012/08/13 08:33:08
    • Location: Cincinnati, Ohio USA
    • Status: offline
    Re: Chaining DMA? 2021/01/13 13:48:43 (permalink)
    5 (1)
    Really has nobody ever used chaining of DMA before? Anybody?
    Looks like it because my FAE is not answering me as well.
    Thanks,
    Gordon
    #2
    MisterHemi
    Super Member
    • Total Posts : 326
    • Reward points : 0
    • Joined: 2017/11/02 12:24:21
    • Location: Commerce, CA USA
    • Status: offline
    Re: Chaining DMA? 2021/01/13 21:47:54 (permalink)
    4 (1)
    I would think that should work. I've used DMA chaining...
     
    USB DMA -> buffer -> General Purpose DMA -> I2S
     
     

    My configuration:
    MacBook Pro (Retina, 15-inch, Mid 2015) with MacOS Mojave (10.14.6) and MPLAB X IDE v5.30
     
    Curiosity PIC32MZ EF 1 & 2, PIC24F Curiosity, XPRESS EVAL BOARD (PIC16F18855), SAMA5D3 Xplained and various custom boards.
    #3
    al_bin
    Super Member
    • Total Posts : 225
    • Reward points : 0
    • Joined: 2011/02/11 06:28:47
    • Location: 0
    • Status: offline
    Re: Chaining DMA? 2021/01/14 00:32:49 (permalink)
    0
    Use SPI and 3 x 74HC595 or similar ?
    #4
    Wavelength
    Super Member
    • Total Posts : 312
    • Reward points : 0
    • Joined: 2012/08/13 08:33:08
    • Location: Cincinnati, Ohio USA
    • Status: offline
    Re: Chaining DMA? 2021/01/14 09:00:23 (permalink)
    4 (1)
    MisterHemi,
    Your not chaining in that instance. First off the USB is interrupt driven on a packet basis (with ping pong buffers) and the I2S is DMA on a need to fill the buffer ever 64bits.
     
    What I need to know is the use of the CHAIN variable in the DMA controller. I am not sure how that works. Does the chain work at the end of a dma sequence or can you use each time the DMA is activated.
    Thanks,
    Gordon
    #5
    Wavelength
    Super Member
    • Total Posts : 312
    • Reward points : 0
    • Joined: 2012/08/13 08:33:08
    • Location: Cincinnati, Ohio USA
    • Status: offline
    Re: Chaining DMA? 2021/01/14 09:01:30 (permalink)
    0
    Al,
    The whole idea for this was not to use any serial method at all, but parallel.
    Thanks,
    Gordon
    #6
    MisterHemi
    Super Member
    • Total Posts : 326
    • Reward points : 0
    • Joined: 2017/11/02 12:24:21
    • Location: Commerce, CA USA
    • Status: offline
    Re: Chaining DMA? 2021/01/14 09:28:24 (permalink)
    4 (1)
    I remember seeing this, it may be helpful:
    tutorial.cytron.io/2017/09/01/i2s-pic32mxmz-direct-memory-access-dma/
     
     

    My configuration:
    MacBook Pro (Retina, 15-inch, Mid 2015) with MacOS Mojave (10.14.6) and MPLAB X IDE v5.30
     
    Curiosity PIC32MZ EF 1 & 2, PIC24F Curiosity, XPRESS EVAL BOARD (PIC16F18855), SAMA5D3 Xplained and various custom boards.
    #7
    Wavelength
    Super Member
    • Total Posts : 312
    • Reward points : 0
    • Joined: 2012/08/13 08:33:08
    • Location: Cincinnati, Ohio USA
    • Status: offline
    Re: Chaining DMA? 2021/01/14 09:54:59 (permalink)
    5 (1)
    MisterHemi,
    Thanks I have 22 products with USB Audio and I am understand DMA really well. I am asking about chaining two DMA channels together. I can't seem to get any FAE help or answers here.
    Thanks,
    Gordon
    #8
    MisterHemi
    Super Member
    • Total Posts : 326
    • Reward points : 0
    • Joined: 2017/11/02 12:24:21
    • Location: Commerce, CA USA
    • Status: offline
    Re: Chaining DMA? 2021/01/14 11:00:50 (permalink)
    0
    You're welcome.
    I think in that link he has 2 DMA channels chained together, if I remember correctly.
     
    I could be thinking of the wrong web page. There was one I remember where there were ping-pong/double buffering examples and another one with chaining where one fired then upon completion it fired another DMA channel.

    My configuration:
    MacBook Pro (Retina, 15-inch, Mid 2015) with MacOS Mojave (10.14.6) and MPLAB X IDE v5.30
     
    Curiosity PIC32MZ EF 1 & 2, PIC24F Curiosity, XPRESS EVAL BOARD (PIC16F18855), SAMA5D3 Xplained and various custom boards.
    #9
    Wavelength
    Super Member
    • Total Posts : 312
    • Reward points : 0
    • Joined: 2012/08/13 08:33:08
    • Location: Cincinnati, Ohio USA
    • Status: offline
    Re: Chaining DMA? 2021/01/14 12:16:20 (permalink)
    0
    MisterHemi,
    Sorry that is just basic DMA, nothing chained. There is this one:
    https://people.ece.cornell.edu/land/courses/ece4760/PIC32/index_DMA.html
    Which states chain indicates at the end of one length the chained DMA channel gets invoked on the next event then back to the original. That is NOT what I want to do.
    I need one channel to write out 16 bits to PORTB, then PMP 8 bits and then I will use the -WR pulse to then latch the full 24 bits to the world.
    So in a sense I need to chain the two DMA so the 16bits is first then the PMP second. I am not sure that is possible. It appears everyone is using chaining in a ping pong manner so when one is done the second one starts up.
    Thanks,
    Gordon
    #10
    al_bin
    Super Member
    • Total Posts : 225
    • Reward points : 0
    • Joined: 2011/02/11 06:28:47
    • Location: 0
    • Status: offline
    Re: Chaining DMA? 2021/01/14 16:01:24 (permalink)
    0
    Why can't the timer fire up two DMA channels simultaneously?
     
    Albert
    #11
    Morce323
    New Member
    • Total Posts : 9
    • Reward points : 0
    • Joined: 2020/05/04 01:30:17
    • Location: 0
    • Status: online
    Re: Chaining DMA? 2021/01/14 17:18:52 (permalink)
    5 (1)
    If what you require is secobd DMA to trigger right after first one is finished (but not at the same time), it should be possible. I dont remember exact register names, but following should be configurable:

    Set both dmas to trigger from the same timer (i believe it should be possible, but never tried using same source for multiple dmas), chain them together (finishing first enables second and finishing second enables first - or just keep first enabled all the time).

    If I remember correctly, you can set the second dma to accept triggers even while in disabled state, so it should trigger instantly after being enabled by first dma.

    (Edit: DCHxCON.CHAED)

    Alternatively, if triggering from same source would not work, you might get away by triggering second dma from first dma interrupt (as long as you set it to fire only from finished transfer).

    Also, doubling timer frequency and using classic "ping-pong" chaining (1 enables 2, 2 enables 1, same trigger) would probably work as well (as long as you manage to latch out data before next trigger).
     
    edit: Ok, got it working, tested on PIC32MZ2064DAS, because thats what I have at hand. It appears that triggering multiple DMAs from same source is totally ok. However using DMA interrupt to trigger DMA is NOT ok, because it requires to manualy clear DCHxINT in order to trigger again. Clearing it using another DMA wont work (at least it didnt for me).
     
    I have put together following sample, it uses 3 DMAs in total. DMA0 feeds buffer (data_in) to DMA1 and DMA2. DMA1 copies first two bytes from buffer into buffer_out, DMA2 does the same for second two bytes.
     
    All DMAs react to _TIMER_2_VECTOR, but DMA0 has lower priority than DMA1 & DMA2, which seems to work fine (geting expected output). More testing is deffinitely required before using in production. :) If you can get any other trigger source for DMA0 (Input Change Notification from PMP WR pin should be fine), than I would advise doing so.
     
    char  __attribute__((coherent)) buffer[5] = { 0 };

    char  __attribute__((coherent)) buffer_out[5] = { 0 };

    const char * data_in =
        "A01\n" "B02\n" "C03\n" "D04\n" "E05\n" "F06\n" "G07\n" "H08\n" "I09\n";

    void dma_init() {
        
        PMD7bits.DMAMD = 0;
            
        // setup timer
        T2CON = (7 << _T2CON_TCKPS_POSITION);   // 256 prescaler
        TMR2 = 0;
        PR2 = UINT16_MAX;   // just using long timer to make sure I can catch change
        T2CONSET = _T2CON_ON_MASK;  // turn timer on

        DMACON = (1 << _DMACON_ON_POSITION);    // Enable DMA module if it hasn't been
        DCRCCON = 0;    // crc check module is disabled
        
        /* DMA 0 - feeds buffer */
        
        DCH0CON     =   0;
        DCH0ECON    =   (_TIMER_2_VECTOR << _DCH3ECON_CHSIRQ_POSITION) |    // trigger cell transfer event on _DMA_2_VECTOR (when DMA2 finishes)
                        (1 << _DCH3ECON_SIRQEN_POSITION);   // start on matching interrupt
        
        DCH0CON     =   (2 << _DCH0CON_CHPRI_POSITION); // channel priority has to be lower than DMA1 & DMA2
        
        DCH0CSIZ    =   4;  // copy 4 bytes at once
        DCH0SSIZ    =   strlen(data_in);
        DCH0SSA     =   KVA_TO_PA(data_in);  
        
        DCH0DSIZ    =   4;
        DCH0DSA     =   KVA_TO_PA(buffer);  // feed into buffer
        
        /* DMA 1 - sends byte 1 - 2 */
        
        DCH1CON     =   0;
        DCH1ECON    =   (_TIMER_2_VECTOR << _DCH1ECON_CHSIRQ_POSITION) |    // trigger cell transfer event on _TIMER_1_VECTOR
                        (1 << _DCH1ECON_SIRQEN_POSITION);   // start on matching interrupt
        
        DCH1CON     =   (1 << _DCH1CON_CHCHNS_POSITION) |   // enable when higher dma finishes
                        (1 << _DCH1CON_CHCHN_POSITION) |    // allow chaining
                        (3 << _DCH2CON_CHPRI_POSITION); // channel priority has to be higher than DMA0
        
        DCH1CSIZ    =   2;  // cell size 2
        
        DCH1SSIZ    =   2;  // source size is 2
        DCH1SSA     =   KVA_TO_PA(buffer);  // bytes 1-2 from buffer

        DCH1DSIZ    =   2;  // dest size 2
        DCH1DSA     =   KVA_TO_PA(buffer_out); // feed into uart
        
        /* DMA 2 - sends byte 3 */
        
        DCH2CON     =   0;
        DCH2ECON    =   (_TIMER_2_VECTOR << _DCH2ECON_CHSIRQ_POSITION) |    // trigger cell transfer event on _TIMER_1_VECTOR
                        (1 << _DCH2ECON_SIRQEN_POSITION);   // start on matching interrupt
        
        DCH2CON     =   (0 << _DCH2CON_CHCHNS_POSITION) |   // enable when lower dma finishes
                        (1 << _DCH2CON_CHCHN_POSITION) |    // allow chaining
                        (1 << _DCH2CON_CHAED_POSITION) |    // register start event when disabled
                        (3 << _DCH2CON_CHPRI_POSITION);     // channel priority has to be higher than DMA0
        
        DCH2CSIZ    =   2;  // cell size 2
        
        DCH2SSIZ    =   2;  // source size 2
        DCH2SSA     =   KVA_TO_PA(buffer + 2);  // byte 3 - 4 from buffer
        
        DCH2DSIZ    =   2;  // dest size 2
        DCH2DSA     =   KVA_TO_PA(buffer_out + 2);     // feed into uart
           
        /* Start DMAs 0 & 1 */
        DCH0CONSET  = _DCH0CON_CHEN_MASK;
        DCH1CONSET  = _DCH1CON_CHEN_MASK;
        
        while(1) {
            uart_directf("OUT: %s" CRLF, buffer_out);
            delay_us(100 * 1000);
        }
    }

    post edited by Morce323 - 2021/01/15 06:07:05
    #12
    Wavelength
    Super Member
    • Total Posts : 312
    • Reward points : 0
    • Joined: 2012/08/13 08:33:08
    • Location: Cincinnati, Ohio USA
    • Status: offline
    Re: Chaining DMA? 2021/01/15 07:31:01 (permalink)
    0
    Morce,
    Thanks that's what I was thinking last night with the priority and so forth that should work.
     
    I was actually thinking that instead of keying off the finish of the DMA to actually just use priority and trigger both from the same timer. Have the PMP lower than the PORTB write and so the timer pops and PORTB DMA comes active then when it's done the PMP DMA would go active and trigger the latch so all 24 bits comes out at the same time.
     
    Appreciate the work! Thanks,
    Gordon
    #13
    Jump to:
    © 2021 APG vNext Commercial Version 4.5