AnsweredAssumed Answered

MPC5748 eDMA Channel Linking Problem

Question asked by Anthony Buonassisi on Mar 22, 2020
Latest reply on Mar 28, 2020 by Anthony Buonassisi

Hi all,

I am using the MPC5748G's (dev-kit) eDMA to transfer data from one buffer in SRAM to another and have found that my configuration of linking two TCDs does not behave as I expect. I have the following two data buffers:

 

uint32_t src[2]; // data source
uint32_t dst[4]; // data destination

 

I would like to continually do the following: transfer src[0]->dst[0] and src[1]->dst[1], then after waiting one second transfer src[0]->dst[2] and src[1]->dst[3]. I have written the following configuration to do this in two minor loops, where src[0] is transferred using TCD1 which then links to src[1] being transfered by TCD2. I have observed that the first major loop behaves correctly but the second minor loop of the second major loop does not (described in detail below).

 

main.c

static uint32_t src[2];

static uint32_t dst[4];

 

void ISR_1Hz() {

   /* Update source buffer for debugging */

   static uint8_t data = 0;

   src[0] = data;

   src[1] = data + 1;

   data += 2;

   data %= 256;

 

/* Start DMA transfers */

EDMA.TCD[1].CSR.B.START = 1;

}

 

void main() {

    /* Configure TCD 1 */

    EDMA.TCD[1].SADDR.B.SADDR = (uint32_t)&src[0];

    EDMA.TCD[1].ATTR.B.SMOD = 0;

    EDMA.TCD[1].ATTR.B.SSIZE = 2;            // 32-bit source size

    EDMA.TCD[1].SOFF.B.SOFF = 0;

    EDMA.TCD[1].SLAST.B.SLAST = 0;

    EDMA.TCD[1].DADDR.B.DADDR = (uint32_t)&dest[0];

    EDMA.TCD[1].ATTR.B.DMOD = 0;

    EDMA.TCD[1].ATTR.B.DSIZE = 2;            // 32-bit destination size

    EDMA.TCD[1].DOFF.B.DOFF = 8;             // increment dest 8-bytes each minor loop

    EDMA.TCD[1].DLASTSGA.B.DLASTSGA = -16;   // decrement dest 16-bytes each major loop

    EDMA.TCD[1].NBYTES.MLNO.B.NBYTES = 4;    // transfer 4-bytes per minor loop

    EDMA.TCD[1].CITER.ELINKYES.B.ELINK = 1;  // enable channel-channel linking after minor loops

    EDMA.TCD[1].CITER.ELINKYES.B.LINKCH = 2; // enable ch2 for linking

    EDMA.TCD[1].CITER.ELINKYES.B.CITER = 2;  // 2 minor loops per major loop

    EDMA.TCD[1].BITER.ELINKYES.B.BITER = 2;  // same as above

    EDMA.TCD[1].BITER.ELINKYES.B.ELINK = 1;  // same as above

    EDMA.TCD[1].BITER.ELINKYES.B.LINKCH = 2; // same as above

    EDMA.TCD[1].CSR.B.BWC = 0;

    EDMA.TCD[1].CSR.B.INTMAJOR = 0;

    EDMA.TCD[1].CSR.B.MAJORELINK = 1;        // enable channel-channel linking after major loops

    EDMA.TCD[1].CSR.B.MAJORLINKCH = 2;       // enable ch2 for linking

 

    /* Configure TCD 2 */

    EDMA.TCD[2].SADDR.B.SADDR = (uint32_t)&src[1];

    EDMA.TCD[2].ATTR.B.SMOD = 0;

    EDMA.TCD[2].ATTR.B.SSIZE = 2;

    EDMA.TCD[2].SOFF.B.SOFF = 0;

    EDMA.TCD[2].SLAST.B.SLAST = 0;

    EDMA.TCD[2].DADDR.B.DADDR = (uint32_t)&dest[1];

    EDMA.TCD[2].ATTR.B.DMOD = 0;

    EDMA.TCD[2].ATTR.B.DSIZE = 2;

    EDMA.TCD[2].DOFF.B.DOFF = 8;

    EDMA.TCD[2].DLASTSGA.B.DLASTSGA = -16;

    EDMA.TCD[2].NBYTES.MLNO.B.NBYTES = 4;

    EDMA.TCD[2].CITER.ELINKNO.B.ELINK = 0;   // same config as TCD1 but no linking

    EDMA.TCD[2].CITER.ELINKNO.B.CITER = 2;

    EDMA.TCD[2].BITER.ELINKNO.B.BITER = 2;

    EDMA.TCD[2].BITER.ELINKNO.B.ELINK = 0;

    EDMA.TCD[2].CSR.B.BWC = 0;

    EDMA.TCD[2].CSR.B.INTMAJOR = 0;

 

    /* Do nothing else */

    for(;;) {}

}

Debugger Results

I have seen the following behaviour in my debugging environment:

  • SADDR and DADDR for both TCDs are incremented/decremented correctly for the first major loop
  • data is correctly transferred during the first major loop
  • data is correctly transferred during the first minor loop of the second major loop
  • data is incorrectly transferred during the second minor loop of the second major loop
    • TCD1 correctly transfers data from src[0]->dst[2]
    • TCD2 is not triggered so the transfer of src[1]->dst[3] does not occur 
    • Before this transfer takes place, EDMA.TCD[1].CSR.B.MAJORELINK is cleared somehow
    • Before this transfer takes place, EDMA.TCD[1].CITER.ELINKYES.B.ELINK = 1 and EDMA.TCD[1].CITER.ELINKYES.B.LINKCH = 2, which makes me think that TCD2 should be triggered, but it is not
    • After this transfer takes place, EDMA.TCD[2].DADDR.B.DADDR is not changed which confirms that TCD1 did not trigger TCD2
  • on the first minor loop of the third major loop, TCD1 correctly transfers src[0]->dst[0], and TCD2 is triggered which transfers src[1]->dst[3] which is incorrect but I guess makes sense if it was not triggered during the second minor loop of the second major loop

 

Please advise what I can change to my TCD configuration to solve this issue. Alternatively, if there is a better suited approach to this problem or if I should clarify any part of my question, please let me know.

 

Cheers,

Anthony B

Outcomes