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
1,199 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
1,000 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
1,001 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.

1,000 Views
anthonybuonassi
Contributor II

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

0 Kudos
1,000 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
1,000 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