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.

uDMA ScatterGather with GPIO

I'm working with the LM4F230, trying to get uDMA ScatterGather mode working off a GPIO request.  Currently I have the DMA working in basic mode off a GPIOA interrupt request that occurs every 20us.  I would like to now implement scatterGather so that I don't have to set up the next transfer every 20us.  Working off the udma_uart_sg.c example I've copied over the task list and scattergather initialization which has 6 tasks and then ends where the last 3 tasks put dummy data into the SSI tx buffer.  Basically what I'd like to see at this point is the SPI clock run for those last 3 tasks.  I've been unable to get this working.  Any suggestions?  Initialization code below.

Thanks

 

#pragma DATA_ALIGN(ucControlTable, 1024)
UINT8 ucControlTable[1024];

static unsigned char g_ucSrcBuf[1024];
static unsigned char g_ucSrcBuf1[300];
static unsigned char g_ucDstBuf1[123];
static unsigned char g_ucSrcBuf2[645];
static unsigned char g_ucDstBuf2[345];
static unsigned char g_ucSrcBuf3[79];
static unsigned char g_ucDstBuf3[556];
static unsigned char g_ucDstBuf[1024];
#define SRC_IDX_1 0
#define SRC_IDX_2 sizeof(g_ucSrcBuf1)
#define SRC_IDX_3 (SRC_IDX_2 + sizeof(g_ucSrcBuf2))
#define DST_IDX_1 0
#define DST_IDX_2 sizeof(g_ucDstBuf1)
#define DST_IDX_3 (DST_IDX_2 + sizeof(g_ucDstBuf2))

tDMAControlTable g_TaskTableSrc[] =
{
//
// Task 1: copy source buffer fragment 1
//
uDMATaskStructEntry(sizeof(g_ucSrcBuf1), UDMA_SIZE_8,
UDMA_SRC_INC_8, &g_ucSrcBuf[SRC_IDX_1],
UDMA_DST_INC_8, g_ucSrcBuf1,
UDMA_ARB_8, UDMA_MODE_PER_SCATTER_GATHER),

//
// Task 2: copy source buffer fragment 2
//
uDMATaskStructEntry(sizeof(g_ucSrcBuf2), UDMA_SIZE_8,
UDMA_SRC_INC_8, &g_ucSrcBuf[SRC_IDX_2],
UDMA_DST_INC_8, g_ucSrcBuf2,
UDMA_ARB_8, UDMA_MODE_PER_SCATTER_GATHER),

//
// Task 3: copy source buffer fragment 3
//
uDMATaskStructEntry(sizeof(g_ucSrcBuf3), UDMA_SIZE_8,
UDMA_SRC_INC_8, &g_ucSrcBuf[SRC_IDX_3],
UDMA_DST_INC_8, g_ucSrcBuf3,
UDMA_ARB_8, UDMA_MODE_PER_SCATTER_GATHER),

//
// Task 4: copy fragment buffer 1 to SSI
//
//
uDMATaskStructEntry(sizeof(g_ucSrcBuf1), UDMA_SIZE_8,
UDMA_SRC_INC_8, g_ucSrcBuf1,
UDMA_DST_INC_NONE, (void *)(SSI0_BASE + SSI_O_DR),
UDMA_ARB_8, UDMA_MODE_PER_SCATTER_GATHER),

//
// Task 5: copy fragment buffer 2 to SSI
//
//
uDMATaskStructEntry(sizeof(g_ucSrcBuf2), UDMA_SIZE_8,
UDMA_SRC_INC_8, g_ucSrcBuf2,
UDMA_DST_INC_NONE, (void *)(SSI0_BASE + SSI_O_DR),
UDMA_ARB_8, UDMA_MODE_PER_SCATTER_GATHER),

//
// Task 6: copy fragment buffer 3 to SSI
// mode is basic since this is last task
//
uDMATaskStructEntry(sizeof(g_ucSrcBuf3), UDMA_SIZE_8,
UDMA_SRC_INC_8, g_ucSrcBuf3,
UDMA_DST_INC_NONE, (void *)(SSI0_BASE + SSI_O_DR),
UDMA_ARB_8, UDMA_MODE_BASIC)
};


// initialize interrupt

ROM_GPIOIntTypeSet(GPIO_PORTA_BASE, GPIO_PIN_3, GPIO_FALLING_EDGE);
ROM_GPIOPinIntEnable(GPIO_PORTA_BASE, GPIO_PIN_3);

ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA); // Enable uDMA controller at system level
ROM_uDMAEnable(); // Enable the uDMA controller
ROM_uDMAControlBaseSet(ucControlTable); // Point at the control table to use for channel control structures

ROM_uDMAChannelDisable(UDMA_CHANNEL_4); // Ensure channel is disabled before modifying register
ROM_uDMAChannelAssign(UDMA_CH4_GPIOA);
ROM_GPIODMATriggerEnable(GPIO_PORTA_BASE, GPIO_PIN_3);
ROM_uDMAChannelAttributeDisable(UDMA_CHANNEL_4,
                                                            UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST |
                                                            UDMA_ATTR_HIGH_PRIORITY |
                                                            UDMA_ATTR_REQMASK);

ROM_uDMAChannelScatterGatherSet(UDMA_CHANNEL_4, 6, g_TaskTableSrc, TRUE);
ROM_uDMAChannelEnable(UDMA_CHANNEL_4);

  • Phil,

    When you say that you have been unable to get this working, can you describe exactly what is not happening?  Are you just not seeing the SPI clock toggle?  Have you verified that the SSI module operates independently of the DMA scatter gather operation with basic DMA? 

    Thanks,

    Sean

  • Sean-

    Basically I'm not seeing the task list being executed, primarily I'm looking for the SPI clock to run.  Yes I have verified that the SPI and DMA work independently using BASIC mode.  This initialization here works for basic mode, upon GPIO interrupt the DMA transfers data to the SPI tx buffer.

    uDMAChannelControlSet(UDMA_CHANNEL_4 | UDMA_PRI_SELECT,
                             UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_NONE |
                             UDMA_ARB_16);

    uDMAChannelTransferSet(UDMA_CHANNEL_4 | UDMA_PRI_SELECT, UDMA_MODE_BASIC,
                             dma.txBuff, (void *)(SSI0_BASE + SSI_O_DR), 6);

  • So the first task in the list is actually executing, that task is encountering a bus error where the Bus Error Status bit is being set so it is not continuing on to the next task....working on   determining source of bus error...

  • I have not any luck resolving the bus error when using the GPIO as the trigger for the dma transfer.  Below is the latest thing I've tried, which should transfer 0xFF data from the source buffer to a destination buffer which is initialized to 0x00 data.  I'm not seeing any data transfer taking place in task 1.  After the first GPIO event occurs, upon halting the 'DMA Bus Error Status' flag is set.  Any ideas on why this isn't working?

    Thanks

    tDMAControlTable g_TaskTableSrc[] =
    {

    // Task 1

    uDMATaskStructEntry(sizeof(dma.txBuff), UDMA_SIZE_16,
    UDMA_SRC_INC_16, dma.txBuff,
    UDMA_DST_INC_16, dma.rxBufA,
    UDMA_ARB_2, UDMA_MODE_MEM_SCATTER_GATHER),

    // Task 2: copy fragment buffer 3 to SSI

    uDMATaskStructEntry(sizeof(dma.txBuff), UDMA_SIZE_16,
    UDMA_SRC_INC_16, dma.txBuff,
    UDMA_DST_INC_16, dma.rxBufA,
    UDMA_ARB_2, UDMA_MODE_BASIC)

    };

    ROM_GPIOIntTypeSet(GPIO_PORTA_BASE, GPIO_PIN_3, GPIO_FALLING_EDGE);
    ROM_GPIOPinIntEnable(GPIO_PORTA_BASE, GPIO_PIN_3);
    ROM_GPIOPinIntClear(GPIO_PORTA_BASE, GPIO_PIN_3);

    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA); // Enable uDMA controller at system level
    ROM_uDMAEnable(); // Enable the uDMA controller
    ROM_uDMAControlBaseSet(ucControlTable); // Point at the control table to use for channel control structures

    ROM_uDMAChannelDisable(UDMA_CHANNEL_4); // Ensure channel is disabled before modifying register
    ROM_uDMAChannelAssign(UDMA_CH4_GPIOA);
    ROM_GPIODMATriggerEnable(GPIO_PORTA_BASE, GPIO_PIN_3);
    ROM_uDMAChannelAttributeDisable(UDMA_CHANNEL_4,
                        UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST |
                        UDMA_ATTR_HIGH_PRIORITY |
                        UDMA_ATTR_REQMASK);

    for(ii=0; ii<6; ii++)
    {
    dma.txBuff[ii] = 0xFFFF;
    dma.rxBufA[ii] = 0x0000;
    }

    uDMAChannelControlSet(UDMA_CHANNEL_4, UDMA_SIZE_16 |
                                              UDMA_SRC_INC_16 | UDMA_DST_INC_16 | UDMA_ARB_2);
    uDMAChannelTransferSet(UDMA_CHANNEL_4, UDMA_MODE_PER_SCATTER_GATHER,
                                               g_TaskTableSrc, &ucControlTable[UDMA_CHANNEL_4], 2 * 2);

    ROM_uDMAChannelEnable(UDMA_CHANNEL_4);

  • Phil,

    I wrote a test to see if I could get the scatter gather working with two memory to memory transfers like you last example.  It appears to be working with your code except I used scattergatherset instead of controlset and transferset:

    ROM_uDMAChannelScatterGatherSet(UDMA_CH18_TIMER0A, 2, g_TaskTableSrc, false);

    (I used the timers instead of the GPIO to generate triggers)  Perhaps there is a problem with using the UDMA_MODE_PER_SCATTER_GATHER and not UDMA_MODE_MEM_SCATTER_GATHER.  Other than that, I don't see anything else that would be causing problems.  I would recommend using UDMA_CH4_GPIO4 in all locations you are using UDMA_CHANNEL_4 (except in the ucControlTable index).  

    Can you send the entire C source file for the 2 copy example and I will try to run it unmodified?  Which toolchain are you using?

    Sean

  • Sean-

    Thanks for the quick response.  It looks like my problem was with the UDMA_CHANNEL_4 which was defined as 4.  I was not passing the offset for third peripheral on the channel.  I was thrown off looking at the udma_uarg_sg.c example because they just pass the channel number (UDMA_CHANNEL_UART1TX) which is a separate list of definitions in the udma.h file than where the individual peripheral channel definitions are.  So what they have only works if you are using peripheral 0 on the channel. Seems like lines 238-264 in udma.h are unnecessary.  Thanks again for your support.

    Phil

  • Phil,

    Glad to hear it's working.  Yes, the lines in udma.h that list the UDMA_CHANNEL_* macros are unnecessary in the newer devices.  We have an issue open to fix the comments in that regard.

    Thanks,

    Sean