This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP430F6747A: DMA transfer working without interrupts and bugged with interrupts

Part Number: MSP430F6747A

Tool/software:

Hi,

I've been trying to use DMA for large data transfers at high speed and i came accross an issue when using DMA's interrupts.

My program is trying to send a buffer (9638 bytes) to the eUSCI A0 module configured in uart mode. The uart configuration in itself

is working as i'm able to send data through it to my PC with a serial cable.

I made two simple test functions to send the same buffer with DMA, one function uses flag polling and the other uses DMA's interrupts. Here is the code :

static void dma_send(const uint8_t *buf, size_t len)
{
    DMACTL0 = DMA0TSEL_17; // UCA0TXIFG

    DMA0SA = (uint32_t)buf;
    DMA0DA = (uint32_t)(&UCA0TXBUF);
    DMA0SZ = len;

    DMA0CTL = (
        DMADT_0        // single transfer mode
        | DMADSTINCR_0 // destination addess fixed
        | DMASRCINCR_3 // source address incremented
        | DMADSTBYTE
        | DMASRCBYTE
        | DMALEVEL     // trigger type: level detection
    );

    hw_toggle_led1();

    DMA0CTL |= DMAEN;
    while (!(DMA0CTL & DMAIFG));

    hw_toggle_led1();
}

PLACE_INTERRUPT(isr_dma)
#pragma vector=DMA_VECTOR
static void __interrupt isr_dma(void)
{
    __low_power_mode_off_on_exit();

    switch (__even_in_range(DMAIV, DMAIV_DMA0IFG)) {
    case DMAIV_DMA0IFG: {
        DMA0CTL &= ~DMAIE;
        break;
    }
    }
}

static void dma_send_irq(const uint8_t *buf, size_t len)
{
    DMACTL0 = DMA0TSEL_17; // UCA0TXIFG

    DMA0SA = (uint32_t)buf;
    DMA0DA = (uint32_t)(&UCA0TXBUF);
    DMA0SZ = len;

    DMA0CTL = (
        DMADT_0        // single transfer mode
        | DMADSTINCR_0 // destination address fixed
        | DMASRCINCR_3 // source address incremented
        | DMADSTBYTE
        | DMASRCBYTE
        | DMALEVEL     // trigger type: level detection
        | DMAIE        // enable interrupts
    );

    hw_toggle_led1();

    DMA0CTL |= DMAEN;

    __low_power_mode_0();

    hw_toggle_led1();
}
For all my tests, both MCLK and SMCLK (which is used to source the uart) are seted up with DCOCLK running at 25 MHz, using REFOCLK as reference, so the frequency is not really accurate.
I'm calling these functions and pass the buffer as parameter. With "dma_send()" i have no issue, it's working fine, i tried from baudrate 57'600 and up to 3'000'000.
With "dma_send_irq()" however, it seems to be working from baudrate 57'600 up to 1'382'400, but higher than that it's completely bugged, i'm receiving garbage characters on my computer terminal and sometimes the MSP itself crashes.
I made the tests with edge trigger detection as well but i'm getting the same result or worse.
I'd prefer to use the interrupts because the goal would be to use low power mode during the transfer, we're trying to achieve maximum data rate to transfer around 2M bytes of data as quick as possible in the real case application.
Is there an explanation for this behaviour with interrupts enabled ?
Thanks.

  • The use of DMALEVEL=1 worries me given: "When DMALEVEL = 1, level-sensitive triggers are used. For proper operation, level-sensitive triggers can
    only be used when external trigger DMAE0 is selected as the trigger."

  • Yes as i mentionned in my initial message i tried to use edge detection instead of level detection but i'm getting worse results on average. It usually works fine at lower baudrate but when going higher i'm getting garbage characters too on my PC terminal.

    When using edge trigger, i set the DMA0SA to "buf + 1" and DMA0SZ to "len - 1", and write the first character of the buffer to UCA0TXBUF manually in order to ensure the proper first edge trigger for the DMA.

  • I would do something to verify the operation of that PC terminal at high bit rates.

    Or examine the data stream using some variety of logic analyzer.

    A cheap test would be to put another F6747 on the receive side.

  • I don't have another MSP for now unfortunately, i'm not sure how i would be able to verity if the transfer from one to the other completed successfully though if i have no exterval way to visualize what's happening inside.

  • Send a checksum.

  • Looking at the device errata I would say that DMA9 would end any chance of my using DMA for serial I/O. A different problem (missed triggers) but a serious one.

  • Yeah i looked at the errata and saw DMA9 too but for some reason thought this might be avoidable. Now that i'm looking at it again, i guess half the features of DMA are unusable with this MSP ?

    EDIT : Actually, i have no clue since the DMA seems to be working almost fine as long as i'm not using DMA's interrupts (that is, using DMAIE to know when the transfer is finished instead of polling DMAIFG), but this doesn't seem to be related to errata DMA9...

  • That errata effects only the USCI and is about lost triggers.

    Use of the DMA interrupt couldn't be the problem as that would not alter the operation of the DMA. Use of a low power mode could. But with LPM0, the maximum DMA cycle time goes from 4 cycles to 5 so that seems unlikely. Perhaps something in the clock system although that shouldn't be changed by LPM0.

    The DMA could not garble serial data. Duplicate or skip bytes, maybe. But since it can't change what is in the serial output shift register, it can't mangle bits.

**Attention** This is a public forum