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.

TM4C1294KCPDT: Problem aquiring data from ADS8900

Part Number: TM4C1294KCPDT

Hello!

In my design I need to read data from ADS8900 at 500kSPS to Tiva MCU.

I want to do it without interrupts, with uDMA, as during aquisition MCU should process data.

The task is: each time I generate a CONVST pulse I neet to start aquiring next sample, 4100 samples total, and then trigger data processing.

So I need my timer to trigger 3-byte SSI transfer via uDMA, and use another channel to transfer 4100 * 3 bytes triggered by SSI.

First of all, I see a bug in uDMAChannelEnable routine - it cleares other channel enables, as it looks like

HWREG(UDMA_ENASET) = 1 << ui8ChannelNum;

But next I do not see any transfers to SSI. Here is my code:

    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI1);
    GPIOPinConfigure(GPIO_PE4_SSI1XDAT0);
    GPIOPinConfigure(GPIO_PE5_SSI1XDAT1);
    GPIOPinConfigure(GPIO_PB5_SSI1CLK);
    GPIOPinTypeSSI(GPIO_PORTB_BASE, GPIO_PIN_5);
    GPIOPinTypeSSI(GPIO_PORTE_BASE, GPIO_PIN_4);
    GPIOPinTypeSSI(GPIO_PORTE_BASE, GPIO_PIN_5);
    SSIConfigSetExpClk(SSI1_BASE, g_ui32SysClock, SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 22000000, 8);
    SSIAdvModeSet(SSI1_BASE, SSI_ADV_MODE_READ_WRITE);
    SSIAdvFrameHoldEnable(SSI1_BASE);
    SSIEnable(SSI1_BASE);
    SSIDMAEnable(SSI1_BASE, SSI_DMA_RX);

    uDMAEnable();
    uDMAControlBaseSet(pui8ControlTable);
    uDMAChannelAssign(UDMA_CH10_SSI1RX);
    uDMAChannelAssign(UDMA_CH0_TIMER4A);
#define UDMA_CHANNEL_TMR4A  UDMA_CHANNEL_USBEP1RX
    uDMAChannelAttributeDisable(UDMA_CHANNEL_TMR4A, UDMA_ATTR_ALTSELECT | UDMA_ATTR_HIGH_PRIORITY |
                                UDMA_ATTR_REQMASK);
    uDMAChannelControlSet(UDMA_CHANNEL_TMR4A | UDMA_PRI_SELECT, UDMA_SIZE_32 | UDMA_SRC_INC_32 | UDMA_DST_INC_NONE | UDMA_ARB_1);
    uDMAChannelTransferSet(UDMA_CHANNEL_TMR4A | UDMA_PRI_SELECT, UDMA_MODE_AUTO,
                           (void *)ADCReq, (void *)(SSI1_BASE + SSI_O_DR), 3);
    uDMAChannelAttributeEnable(UDMA_CHANNEL_TMR4A, UDMA_ATTR_USEBURST);


    uDMAChannelAttributeDisable(UDMA_CHANNEL_SSI1RX, UDMA_ATTR_ALTSELECT | UDMA_ATTR_HIGH_PRIORITY |
                                UDMA_ATTR_REQMASK);
    uDMAChannelControlSet(UDMA_CHANNEL_SSI1RX | UDMA_PRI_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_1);
    uDMAChannelTransferSet(UDMA_CHANNEL_SSI1RX | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG,
                           (void *)(SSI1_BASE + SSI_O_DR), (void *)ADCData1, 4100 * 3);
    uDMAChannelControlSet(UDMA_CHANNEL_SSI1RX | UDMA_ALT_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_1);
    uDMAChannelTransferSet(UDMA_CHANNEL_SSI1RX | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG,
                           (void *)(SSI1_BASE + SSI_O_DR), (void *)ADCData2, 4100 * 3);
    HWREG(UDMA_ENASET) = (1 << UDMA_CHANNEL_TMR4A) + (1 << UDMA_CHANNEL_SSI1RX);

    GPIOPinTypeTimer(GPIO_PORTL_BASE, GPIO_PIN_4 | GPIO_PIN_5);
    GPIOPinConfigure(GPIO_PL4_T0CCP0);
    GPIOPinConfigure(GPIO_PL5_T0CCP1);
    TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PWM | TIMER_CFG_B_PWM);
    TimerLoadSet(TIMER0_BASE, TIMER_A, g_ui32SysClock / 500000);
    TimerMatchSet(TIMER0_BASE, TIMER_A, TimerLoadGet(TIMER0_BASE, TIMER_A) - 10);
    //TimerDMAEventSet(TIMER0_BASE, TIMER_DMA_TIMEOUT_A);

    TimerLoadSet(TIMER0_BASE, TIMER_B, g_ui32SysClock / 500000);
    TimerMatchSet(TIMER0_BASE, TIMER_B, 100);
    TimerControlLevel(TIMER0_BASE, TIMER_B, true);

    TimerEnable(TIMER0_BASE, TIMER_BOTH);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER4);
    TimerConfigure(TIMER4_BASE, TIMER_CFG_PERIODIC);
    TimerLoadSet(TIMER4_BASE, TIMER_A, g_ui32SysClock / 500000);
    TimerDMAEventSet(TIMER4_BASE, TIMER_DMA_TIMEOUT_A);
    TimerEnable(TIMER4_BASE, TIMER_A);

Timer 0A is used for CONVST generation, Timer 0B - for CS generation, and Timer 4 should trigger uDMA transfers to SSI, but it does not.

What is wrong?

  • That is not a bug in the uDMAChannelEnable() routine. Writing a 0 in the DMAENASET register will not clear that bit. From the datasheet:

  • But debugger shows bit is cleared.

    Anyway, it is not an issue, as I enable both channels with direct register write.

    The question is why transfer to SSI is not triggered at all?

  • Update:

    The enable bit for timer channel is cleared right after timer is enabled. Why?

  • Ok, I solved the issue.

    It's slightly weird, but here is the code fragments:

    uint32_t DMASave[4];
    
    tDMAControlTable MyTaskList[] =
    {
     uDMATaskStructEntry(3, UDMA_SIZE_8, UDMA_SRC_INC_8, ADCReq, UDMA_DST_INC_NONE, SSI1_BASE + SSI_O_DR, UDMA_ARB_4, UDMA_MODE_PER_SCATTER_GATHER),
     uDMATaskStructEntry(4, UDMA_SIZE_32, UDMA_SRC_INC_32, DMASave, UDMA_DST_INC_32, pui8ControlTable, UDMA_ARB_1, UDMA_MODE_MEM_SCATTER_GATHER)
    };
    
    
    uDMa initialization:

        uDMAEnable();
        uDMAControlBaseSet(pui8ControlTable);
        uDMAChannelAssign(UDMA_CH10_SSI1RX);
        uDMAChannelAssign(UDMA_CH0_TIMER4A);
    
        uDMAChannelAttributeDisable(0, UDMA_ATTR_ALTSELECT | UDMA_ATTR_HIGH_PRIORITY |
                                    UDMA_ATTR_REQMASK);
        /*uDMAChannelControlSet(0 | UDMA_PRI_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_NONE | UDMA_NEXT_USEBURST | UDMA_ARB_1);
        uDMAChannelTransferSet(0 | UDMA_PRI_SELECT, UDMA_MODE_BASIC,
                                   (void *)ADCReq, (void *)(SSI1_BASE + SSI_O_DR), 30);*/
    
        uDMAChannelScatterGatherSet(0, 2, MyTaskList, true);
    
        uDMAChannelAttributeEnable(0, UDMA_ATTR_USEBURST);
        memcpy(DMASave, pui8ControlTable, 16);
        uDMAChannelEnable(0);
    

    This works.

    But I have another issue, an will create another topic for it.