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.

MSPM0L1306: No early interrupt firing for DMA with Early Channel Interrupt Threshold set to Half point of transfer size

Part Number: MSPM0L1306
Other Parts Discussed in Thread: SYSCONFIG

Hi,

I'm trying to implement some kind of ping-pong buffering using DMA and the early interrupt mechanism.
However, I get no Early-IRQ ever.
My sysconfig-generated init for the DMA channel 0 looks like this:

static const DL_DMA_Config gDMA_CH0Config = {
    .transferMode   = DL_DMA_FULL_CH_REPEAT_SINGLE_TRANSFER_MODE,
    .extendedMode   = DL_DMA_NORMAL_MODE,
    .destIncrement  = DL_DMA_ADDR_UNCHANGED,
    .srcIncrement   = DL_DMA_ADDR_INCREMENT,
    .destWidth      = DL_DMA_WIDTH_BYTE,
    .srcWidth       = DL_DMA_WIDTH_BYTE,
    .trigger        = DMA_CH0_TRIGGER_SEL_FSUB_0,
    .triggerType    = DL_DMA_TRIGGER_TYPE_EXTERNAL,
};

SYSCONFIG_WEAK void SYSCFG_DL_DMA_CH0_init(void)
{
    DL_DMA_clearInterruptStatus(DMA, DL_DMA_INTERRUPT_CHANNEL0);
    DL_DMA_enableInterrupt(DMA, DL_DMA_INTERRUPT_CHANNEL0);
    DL_DMA_clearInterruptStatus(DMA, DL_DMA_FULL_CH_INTERRUPT_EARLY_CHANNEL0);
    DL_DMA_Full_Ch_setEarlyInterruptThreshold(DMA, DMA_CH0_CHAN_ID, DL_DMA_EARLY_INTERRUPT_THRESHOLD_HALF);
    DL_DMA_enableInterrupt(DMA, DL_DMA_FULL_CH_INTERRUPT_EARLY_CHANNEL0);
    DL_DMA_setSrcIncrement(DMA, DMA_CH0_CHAN_ID, DL_DMA_ADDR_INCREMENT);
    DL_DMA_setTransferSize(DMA, DMA_CH0_CHAN_ID, 48);
    DL_DMA_initChannel(DMA, DMA_CH0_CHAN_ID , (DL_DMA_Config *) &gDMA_CH0Config);
}
SYSCONFIG_WEAK void SYSCFG_DL_DMA_init(void){
    DL_DMA_setSubscriberChanID(DMA, DL_DMA_SUBSCRIBER_INDEX_0, 1);
    SYSCFG_DL_DMA_CH0_init();
}

I then enable and start DMA like that:

    //setting src and dest for dma and then
    DL_DMA_enableChannel(DMA, DMA_CH0_CHAN_ID);
    NVIC_EnableIRQ(DMA_INT_IRQn);

and my interrupt routine looks like this:

void DMA_IRQHandler(void){
    switch (DL_DMA_getPendingInterrupt(DMA)) {

        case DL_DMA_FULL_CH_EVENT_IIDX_EARLY_IRQ_DMACH0: {
           DL_GPIO_togglePins(GPIO_LEDS_PORT,
                GPIO_LEDS_USER_LED_1_PIN | GPIO_LEDS_USER_TEST_PIN);
        } break;

        case DL_DMA_EVENT_IIDX_DMACH0:
        __NOP();
            break;

        default:
        __NOP();
            break;
    }
}

Triggering the DMA using FSUB_0 works like a charm but somehow I can't get the early IRQ event, which I'd expect to
fire after the first half of transfers, so that I can re-populate the first 24bytes in my pingpong buffer.

also it does not work with any of the DL_DMA_EARLY_INTERRUPT_THRESHOLD_*.

However, DL_DMA_EVENT_IIDX_DMACH0 does fire.

thank you for at least leading me into the right direction..

  • Sorry I haven't used this feature before. But according to customer feedback this feature should work well.
    First of all, can you check if the register value is correct?

  • Thank you for your response. That definitely led me into the right direction.
    The error was that DMAPREIRQ in the DMACTL gets reset by the call

    DL_DMA_initChannel(DMA, DMA_CH0_CHAN_ID , (DL_DMA_Config *) &gDMA_CH0Config);

    as you can see:

    __STATIC_INLINE void DL_DMA_configTransfer(DMA_Regs *dma, uint8_t channelNum,
        DL_DMA_TRANSFER_MODE transferMode, DL_DMA_EXTENDED_MODE extendedMode,
        DL_DMA_WIDTH srcWidth, DL_DMA_WIDTH destWidth,
        DL_DMA_INCREMENT srcIncrement, DL_DMA_INCREMENT destIncrement)
    {
        dma->DMACHAN[channelNum].DMACTL =
            ((uint32_t) transferMode | (uint32_t) extendedMode |
                (((uint32_t) destIncrement) << 4) | (uint32_t) srcIncrement |
                ((uint32_t) destWidth << 4) | (uint32_t) srcWidth);
    }

    So the solution is simply to manually set DMAPREIRQ after the initChannel call.

    IMHO the sysconfig tool should be aware of this and order the initialization calls accordingly.