MPC5748 eDMA Channel Linking Problem

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

MPC5748 eDMA Channel Linking Problem

Jump to solution
2,677 Views
anthonybuonassi
Contributor II

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

1 Solution
2,478 Views
davidtosenovjan
NXP TechSupport
NXP TechSupport

I don't like using of .B instance especially with status or control/status registers as it is a source of potential issues. Pay attention to following bulletin:

http://www.nxp.com/files/32bit/doc/eng_bulletin/EB758.pdf 

I would recommend to use .R instance.

View solution in original post

4 Replies
2,479 Views
davidtosenovjan
NXP TechSupport
NXP TechSupport

I don't like using of .B instance especially with status or control/status registers as it is a source of potential issues. Pay attention to following bulletin:

http://www.nxp.com/files/32bit/doc/eng_bulletin/EB758.pdf 

I would recommend to use .R instance.

2,478 Views
anthonybuonassi
Contributor II

Changed all to use .R and it works as intended. Thanks a lot, David!

0 Kudos
Reply
2,478 Views
davidtosenovjan
NXP TechSupport
NXP TechSupport

Hi, are you starting it by TCD0, when you are only using TCD1 and 2? Or there is further info missing?

pastedImage_1.png

0 Kudos
Reply
2,478 Views
anthonybuonassi
Contributor II

My mistake, I copied it to this forum incorrectly. Yes, I've been using TCD[1] to trigger the DMA transfer. I updated the original post.

0 Kudos
Reply