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.

DK-TM4C129X: GPIO-triggered SG DMA stuck "on"

Part Number: DK-TM4C129X


I have built a uDMA scatter-gather DMA task list which is triggered by a falling edge of an external ADC BUSY signal on a GPIO A7.  The task list writes four 16-bit words to the SSI1 transmit FIFO, writes 0x80 to GPIO_PORTA_AHB_BASE+GPIO_O_ICR to attempt to clear the DMA request, then copies the starting state of the primary uDMA DMACHCTL back into that word to loop the DMA.  Prior to adding the loop task, I got one 56(=14*4)-pulse burst on the SSI on starting the uDMA, indicating that the SSI is set up correctly and the DMA transfer is working.

However, when I add the loop task, I get a continuous stream of clock pulses on the SSI, instead of the expected 56-pulse burst, once after each falling edge of GPIO A7.  Reducing the GPIO A7 trigger pulse frequency to 10 KHz has no effect on the continuous stream.  This indicates to me that the DMA request is stuck "on."  Writing to GPIO_O_ICR doesn't help.  How do I clear the request, to prevent continuous clock pulses?

Here is the start of the channel control structure table, just prior to starting the process:

Here is the task list pointed to by the primary entry above:

Here are the GPIO register contents:

In symbolic form, here are the primary channel controls structure and task contents, some of which is initialized dynamically by a routine similar to uDMATaskStructEntry():

//! Coil pusher primary uDMA entry pointing to task list

const tDMAControlTable adcPusherUdmaPrimary = {

((char *)adcPusherUdmaTask)+sizeof(adcPusherUdmaTask)-1,

&(uDmaCcs[ni::udmaAlternate][ni::adcBusyCoilUdmaChannel].ui32Spare),

UDMA_CHCTL_DSTINC_32 | UDMA_CHCTL_DSTSIZE_32 |

UDMA_CHCTL_SRCINC_32 | UDMA_CHCTL_SRCSIZE_32 |

UDMA_CHCTL_ARBSIZE_4 |

((sizeof(adcPusherUdmaTask)/sizeof(uint32_t)-1) << UDMA_CHCTL_XFERSIZE_S) |

UDMA_CHCTL_XFERMODE_PER_SG,

0

};

uint32_t adcPusherUdmaPrimaryInit;

//! Udma source for pusher self-loop copy

uint32_t adcPusherUdmaRequestClear = ni::adcBusyGpioCoilMask;

//! Udma source for pusher uDMA request clear

...

// Point primary ADC pusher uDMA to task list.

uDmaCcs[ni::udmaPrimary][ni::adcBusyCoilUdmaChannel] = adcPusherUdmaPrimary;

// Save off reinitialization value for loop.

adcPusherUdmaPrimaryInit = adcPusherUdmaPrimary.ui32Control;

// Push a burst of clocks to the SSI.

uDMATaskAssign(

adcPusherUdmaTask[0],

sizeof(adcPusher)/sizeof(adcPusher[0]), UDMA_SIZE_16,

UDMA_SRC_INC_16, adcPusher,

UDMA_DST_INC_NONE, (void *)(ni::adcSsi + SSI_O_DR),

UDMA_ARB_1, UDMA_MODE_MEM_SCATTER_GATHER

);

// Clear uDMA request.

uDMATaskAssign(

adcPusherUdmaTask[1],

1, UDMA_SIZE_32,

UDMA_SRC_INC_32, &adcPusherUdmaRequestClear,

UDMA_DST_INC_32, (void *)(ni::adcBusyGpioCoilPort + GPIO_O_ICR),

UDMA_ARB_4, UDMA_MODE_MEM_SCATTER_GATHER

);

// Loop to repeat the pusher task.

uDMATaskAssign(

adcPusherUdmaTask[2],

1, UDMA_SIZE_32,

UDMA_SRC_INC_32, &adcPusherUdmaPrimaryInit,

UDMA_DST_INC_32,

(void *)&(uDmaCcs[ni::udmaPrimary][ni::adcBusyCoilUdmaChannel].ui32Control),

UDMA_ARB_4, UDMA_MODE_MEM_SCATTER_GATHER

);

Best regards,

Leo Bredehoft

  • The bitmaps referenced above are downloaded here:

  • It works now. I found it necessary to make the first of the tasks a peripheral scatter-gather transfer, to produce single bursts of SSI clocks after the falling edge of GPIO A7. No clearing with GPIO_O_ICR was necessary.

    Here are some interesting points I learned along the way:

    1) To loop, it is only necessary to restore the ui32Control field of the channel control structure, since the first two fields are not modified by the uDMA. This saves some time for the DMA.
    2) Transfers with both increments of the NONE type didn't always seem to work. Thus far, all tasks have a real increment for at least the source or destination.
    3) Scatter-gather task and channel control table entries may not have the ARBSIZE field set to UDMA_ARB_1. UDMA_ARB_4 worked in my case.
    4) Peripheral scatter-gather transfers must have a task in the list which is of the peripheral type.
  • Hi Leo,
    Thanks for sharing the tips!