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.

TM4C123GH6PM: Newbie needs help setting up ADC with uDMA

Part Number: TM4C123GH6PM
Other Parts Discussed in Thread: TM4C123AH6PM, TM4C1294NCPDT

Hello.

I have found a piece of code, on this forum, that is used to set up timer triggered ADC with uDMA. link: https://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/p/546435/2025521

I have read TivaWare user's guide and understood what the functions do, and what's the overall process of setting up 

the whole thing. But, it doesn't work for me. It's giving me zeros in the array dedicated to storing the data.

I will add the summary of what I think the code does, there is some redundancy in code which I will keep in.

I'm using Keil, and have put the TARGET_IS_TM4C123_RB1, PART_TM4C123AH6PM in the preproessor symbols.

  1. start and stop are redundant variables, for measuring how often the interrupts happen, along with the SysTick counter and its handler. Correct me if I'm wrong.
  2. ADCseq0Handler is what triggers when the 8 levels deep FIFO gets full. Then we have a uDMAChannelTransferSet, which should take care of the next 64 samples. Then the FIFO will start to get full, and we go again.
  3. main()    Set the clock frequency, we enable the timer, ADC0, uDMA and portE. We set the SysTick period and set the timer periodic(repeating) to 1/16000 s 
  4. init_ADC()    Sets the ADC's clock to 8 MHz (unneccesary step), disables interrupts and the sequencer. 
  5. StepConfigure configures ADC0 with seq 0 with priority 0, channel 1 as input, to cause an interrupt, and this step is last. (Now what happends with all other steps in the FIFO?)
  6. on specific uDMA channel we disable unwanted properties (no idea waht they're for), and enable burst transfers. Control parameters are primary structure, data size, source addres won't be incremented, since it's all from the same FIFO, destination address is going to be incremented, and we have arbitration after 64 such transfers
  7. We then set the array's address and enable interrupts

I'm getting all 0s in the array. And I have checked on a simple ADC program that an analog input is properly configured. 

I hope someone can help me out with all of this. I feel like all that should be set is set, but since I have no experience with this I can't find the mistake.  

Any advice is also welcome.

UPDATE1: I found out the program gets stuck in the SysTickHandler, which I have removed since it's unnecessary, but then it stops at SS0 Handler.

UPDATE2: After the line"ROM_TimerEnable(TIMER0_BASE, TIMER_A);" the first element gets loaded with the correct value, but all others have the same, presumably random, value. Also, I've put a breakpoint at the beginning of SS0 Handler, but it's never reached?

UPDATE3: There is something wrong with the interrupts, definitely. Basic SysTick Handler wont execute, just stalls. Thanks everyone for pitching in, I hope to resolve this thing soon. 

FINAL UPDATE: Startup had different vector names! That's what was causing all of this. Thanks to Bob Crosby, hope you didn't spend too much time looking at this, cb1_mobile, thanks on the advice, John Piliounis and to Phil LaFayette10, your code was better than mine! UDMA_ARB_1 instead of UDMA_ARB_1024

#include <stdbool.h>
#include <stdint.h>

#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_adc.h"
#include "inc/hw_types.h"
#include "inc/hw_udma.h"
#include "inc/hw_emac.h"
#include "driverlib/debug.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/adc.h"
#include "driverlib/udma.h"
#include "driverlib/emac.h"
#include "driverlib/timer.h"
#include "driverlib/rom.h"


#define ADC_SAMPLE_BUF_SIZE     64

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

static uint16_t ADC_OUT[ADC_SAMPLE_BUF_SIZE];
uint32_t n=0;

void init_ADC(void);
static uint32_t g_ui32DMAErrCount = 0;
static uint32_t g_ui32SysTickCount;
volatile uint32_t start, stop;


void uDMAErrorHandler(void)
{
    uint32_t ui32Status;
    ui32Status = ROM_uDMAErrorStatusGet();
    if(ui32Status)
    {
        ROM_uDMAErrorStatusClear();
        g_ui32DMAErrCount++;
    }
}

void SysTickIntHandler(void)
{
    //
    // Update our system tick counter.
    //
    g_ui32SysTickCount++;
}

void ADCseq0Handler()
{
    stop = g_ui32SysTickCount;
    ADCIntClear(ADC0_BASE, 0);
    n++;


    if(!ROM_uDMAChannelIsEnabled(UDMA_CHANNEL_ADC0))
    {
        uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT, UDMA_MODE_BASIC, (void *)(ADC0_BASE + ADC_O_SSFIFO0), &ADC_OUT, ADC_SAMPLE_BUF_SIZE);


        uDMAChannelEnable(UDMA_CHANNEL_ADC0);
    }

    start = stop;


}

int main(void)
{

    SysCtlClockSet(SYSCTL_SYSDIV_2_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);

    SysCtlDelay(20);

    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);


    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);    //Enable the clock to ADC module
    SysCtlDelay(10); // Time for the peripheral enable to set

    SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);    //Enable the clock to uDMA 
    SysCtlDelay(10);


    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);   //Enables the clock to PORT E
    SysCtlDelay(30);

    ROM_SysTickPeriodSet(SysCtlClockGet() / 1000000); //Sets the period of the SysTic counter to 1us 
    ROM_SysTickIntEnable();
    ROM_SysTickEnable();

    ROM_TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);
    ROM_TimerLoadSet(TIMER0_BASE, TIMER_A, ROM_SysCtlClockGet()/16000 -1);   //TODO: Timer Load Value is set here
    ROM_TimerControlTrigger(TIMER0_BASE, TIMER_A, true);


    GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_2);

    SysCtlDelay(80);

    IntMasterEnable();

    init_ADC();


    TimerEnable(TIMER0_BASE, TIMER_A);

    start = g_ui32SysTickCount;



    while(1)
    {

    }
}

void init_ADC()
{

    ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PIOSC | ADC_CLOCK_RATE_HALF, 1);

    SysCtlDelay(10); // Time for the clock configuration to set

    IntDisable(INT_ADC0SS0);
    ADCIntDisable(ADC0_BASE, 0);
    ADCSequenceDisable(ADC0_BASE,0);
    // With sequence disabled, it is now safe to load the new configuration parameters

    ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_TIMER, 0);	

    ADCSequenceStepConfigure(ADC0_BASE,0,0,ADC_CTL_CH1| ADC_CTL_END | ADC_CTL_IE);

    ADCSequenceEnable(ADC0_BASE,0); //Once configuration is set, re-enable the sequencer
    ADCIntClear(ADC0_BASE,0);

    uDMAEnable(); // Enables uDMA
    uDMAControlBaseSet(ucControlTable);

    ADCSequenceDMAEnable(ADC0_BASE,0);
    // Allows DMA requests to be generated based on the FIFO level of the sample sequencer (SS0)

    uDMAChannelAttributeDisable(UDMA_CHANNEL_ADC0, UDMA_ATTR_ALTSELECT | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK);

    uDMAChannelAttributeEnable(UDMA_CHANNEL_ADC0, UDMA_ATTR_USEBURST);
    // Only allow burst transfers

    uDMAChannelControlSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_1024);


    uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT, UDMA_MODE_BASIC, (void *)(ADC0_BASE + ADC_O_SSFIFO0), &ADC_OUT, ADC_SAMPLE_BUF_SIZE);


    ADCIntEnable(ADC0_BASE,0);
    IntEnable(INT_ADC0SS0);
    uDMAChannelEnable(UDMA_CHANNEL_ADC0); // Enables DMA channel so it can perform transfers

}

  • I am working through your code. I noticed that the link you provided for the starting example is not valid. It would be helpful to me if you would check that link and post it again.
  • Poster Savo's "extra effort" -  in providing his "summary" - is greatly helpful as it (clearly) describes his thought process along w/"logic flow."    

    My group most always "demands such summary" - as it "Keeps the programmer (locked to the process) - while enforcing KISS - due to the "sequence of steps" which are required to, "Reach the end objective."

    It is believed poster's effort (really his method) would be improved if he "better linked his summary to their specific code blocks" which would, "Speed, Ease, & Enhance" program troubleshooting...

    Analyzing such code - w/out reference to such, "Sequential, Distinct Elements" (poster's or the analyst's own) seems an "imperfect method..."

  • Hey,

    I have updated the link.
  • You are probably right, I am not really experienced in proper software development.

  • What "probably" - your, "Reducing the complex "whole" - into a series of  "small, sequential steps"- is a classic "problem solving method" - often described as "KISS."    (Simplify, Structure, Sequence, Success!)

    Now while you've listed those steps w/in your "summary" - you have not, "carried that effort" onto your "distinct code blocks."        Each such code block should be identified (thus related) to its earlier, descriptive summary.      Then - and only then - one can properly, "Test each block individually" which greatly, "Speeds, Eases & Enhances" project/program success.

    You write (only) of your, "Array filling w/zeros" - that's important - yet you make "No mention" of your testing of, "Each code block in their proper progression (order)" - in the focused effort to determine, "where & when" your code "breaks."

    A "quick/dirty" suggestion - feed your µDMA with "fixed values" - which eliminates (any/all) ADC errors - from the equation.     Then "re-run" and see if the array "fills" as expected.

    By breaking your code - then your testing - into the smallest, constituent parts - you "Build your understanding of each" - and significantly raise your odds of success.

    Attacking - as an undisciplined "blob" - (usually a rushed/scattered effort) as too many do here - invites MANY "error sources"  making success most, "unlikely."

  • Hello Savo. I'm not quite sure on the cause of your problem but I can see that from inside your interrupt handler ADCseq0Handler() routine, you check on initializing the uDMA interrupt depended operations within the if{} structure, while those commands have already been issued once in the init_ADC() routine. Remark that piece of if{...}code in your interrupt handler ADCseq0Handler() routine and check again.
    John
  • Hey John,
    Thanks for looking into it. Removing the conditional statement did not help.
  • Have you (yet) tried, "Feeding known values into the "µDMA" (NOT those coming from the ADC) and noting if those "known values" arrive safely w/in your buffer?

    Again - breaking the complex whole - into very small (thus more understandable parts) and testing "each of those" proves vastly superior to, the random "Working thru the code."

    Absence of a clear written plan almost guarantees project errors & delays! "Working thru code" - minus such a plan - is not famed as a "problem solving method..."

    Note: My "careful eye" (as noted by some, here) has detected your statement, "Setting the ADC Clock to 8MHz (not required)."      In fact - such an 8MHz setting rises (beyond) your (not required) is in fact dead wrong!     The ADC must receive a System Clock "greater than or equal to 16MHz" - to meet its spec.    (such is revealed w/in the MCU manual's ADC chapter - and the ADC spec - in the rear of the manual...

  • Savo, please see the following for some snippets of my ADC DMA implementation. Please note I use a TM4C1294NCPDT, so be aware. Also, I don't want to hold your hand in a total-sense by providing copy-paste cookie-cutter code. You'll have to declare the missing variables in appropriate areas. I've tried to comment the code to assist the best I can. I'm not the best programmer, but hopefully this may help you.

    Couple of vars to get you going:

    #define DMA_SAMPLING_FREQ           256000 // Use this for VIRTUAL 16-bit sampling at 1000Hz
    
    // Sampling Rate, determines what frequency to make Timer0A trigger an ADC sample
    uint32_t g_uiSamplingFreq = DMA_SAMPLING_FREQ;

    Main loop:

    // Somewhere in setup/config...
    // Initialize everything needed for sampling ADC with DMA, triggered by a timer
    init_ADC_DMA_SampleTimer();
    
    // Somewhere in main()...
    // DMA Sampling
    DMA_Sample_Start(NUM_DMA_SAMPLES);
    
    // Wait until DMA Data is ready
    while (g_ucDataReady == 0)
    {
    };
    
    // If we have new DMA data, handle it
    if (g_ucDataReady)
    {
        Process_Your_Data();
    }

    Here's the detailed functions...

    bool init_ADC_DMA_SampleTimer(void){
        ////////////// Peripheral Init //////////////////
        // This is good practice; never assume that a complete system reset was done between debugging sessions.
    
        // Disable, Reset, and Enable uDMA and then wait for the peripheral to be ready for access.
        ROM_SysCtlPeripheralDisable(SYSCTL_PERIPH_UDMA);
        ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_UDMA);
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
        while(!(ROM_SysCtlPeripheralReady(SYSCTL_PERIPH_UDMA)));
    
        // Disable, Reset, and Enable ADC0 and then wait for the peripheral to be ready for access.
        ROM_SysCtlPeripheralDisable(SYSCTL_PERIPH_ADC0);
        ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_ADC0);
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
        while(!(ROM_SysCtlPeripheralReady(SYSCTL_PERIPH_ADC0)));
    
        // Disable, Reset, and Enable Timer 0A and then wait for the peripheral to be ready for access.
        ROM_SysCtlPeripheralDisable(SYSCTL_PERIPH_TIMER0);
        ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_TIMER0);
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
        while(!(ROM_SysCtlPeripheralReady(SYSCTL_PERIPH_TIMER0)));
    
        // Disable, Reset, and Enable GPIO Port E and then wait for the peripheral to be ready for access.
        // We want to sample ADC from Pin PE_3
        ROM_SysCtlPeripheralDisable(SYSCTL_PERIPH_GPIOE);
        ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOE);
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
        while(!(ROM_SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOE)));
    
        // Disable, Reset, and Enable GPIO Port N and then wait for the peripheral to be ready for access.
        // We want to toggle PN_0 every time the ADC DMA ISR handler is invoked.
        ROM_SysCtlPeripheralDisable(SYSCTL_PERIPH_GPION);
        ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_GPION);
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);
        while(!(ROM_SysCtlPeripheralReady(SYSCTL_PERIPH_GPION)));
    
        // PN_0 LED Toggle (Uncomment if you're going to test the LED toggle/sampling rate)
        //ROM_GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_0);
        //ROM_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0, ui8Toggle);
    
        /////////////////////////////////////////////////
        ////////////// uDMA Init ////////////////////////
    
        //Enables the uDMA controller for use.
        ROM_uDMAEnable();
    
        // Set uDMA Control Table Address
        ROM_uDMAControlBaseSet(ucControlTable);
    
        // Assign the channel 17 for ADC0 Sequencer 3 for ADC IN
        ROM_uDMAChannelAssign(UDMA_CH17_ADC0_3);
    
        // Put the attributes in a known state.  These should already be disabled by default.
        ROM_uDMAChannelAttributeDisable(UDMA_CH17_ADC0_3, UDMA_ATTR_ALL);
    
        // Set the USEBURST attribute. This is somewhat more efficient bus usage than the default which allows single or burst transfers.
        ROM_uDMAChannelAttributeEnable(UDMA_CH17_ADC0_3, UDMA_ATTR_USEBURST);
    
        // Configure the control parameters for the primary control structure for DMA.
        // ADC FIFO (Src) DOES NOT INCREMENT, YA BUFFOON! Arbitration size: 1
        ROM_uDMAChannelControlSet(UDMA_CH17_ADC0_3 | UDMA_PRI_SELECT,
        UDMA_SIZE_32 | UDMA_SRC_INC_NONE | UDMA_DST_INC_32 | UDMA_NEXT_USEBURST |
        UDMA_ARB_1);
    
        ROM_uDMAChannelControlSet(UDMA_CH17_ADC0_3 | UDMA_ALT_SELECT,
        UDMA_SIZE_32 | UDMA_SRC_INC_NONE | UDMA_DST_INC_32 | UDMA_NEXT_USEBURST |
        UDMA_ARB_1);
    
        // Set up the transfer parameters for the primary control structure.
        // The mode is set to Ping-Pong, TransferSize: 1024
        uDMAChannelTransferSet(UDMA_CH17_ADC0_3 | UDMA_PRI_SELECT,
                               UDMA_MODE_PINGPONG,
                               (void *) (ADC0_BASE + ADC_O_SSFIFO3),
                               g_ulADCValues_A,
                               NUM_DMA_TRANSFERS);
    
        ROM_uDMAChannelTransferSet(UDMA_CH17_ADC0_3 | UDMA_ALT_SELECT,
                               UDMA_MODE_PINGPONG,
                               (void *) (ADC0_BASE + ADC_O_SSFIFO3),
                               g_ulADCValues_B,
                               NUM_DMA_TRANSFERS);
    
        // This function enables a specific uDMA channel for use.  This function must be used to enable a channel before it can be used to perform a uDMA transfer.
        // When a uDMA transfer is completed, the channel is automatically disabled by the uDMA controller.  Therefore, this function should be called prior to
        // starting up any new transfer.
        ROM_uDMAChannelEnable(UDMA_CH17_ADC0_3);
    
        /////////////////////////////////////////////////
        ////////////// ADC0SS3 Init /////////////////////
    
        // Configure the analog ADC function for Pin PE_3.
        ROM_GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3);
    
        // Configure the ADC to use PLL at 480 MHz divided by 15 to get the maximum ADC clock of 32 MHz. This gives 1MSPS Maximum Sampling Rate?
        ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL, 15);
    
        // Set External ADC Reference (VREFA+). BE AWARE TO SET TO INTERNAL IF YOU HAVE NO EXTERNAL REFERENCE!
        ROM_ADCReferenceSet(ADC0_BASE,ADC_REF_EXT_3V);
    
        // Good practice to disable the sequence before configuring it
        ROM_ADCSequenceDisable(ADC0_BASE, DMA_ADC_SEQUENCER);
    
        // Configure ADC to be triggered from Timer
        ROM_ADCSequenceConfigure(ADC0_BASE, DMA_ADC_SEQUENCER, ADC_TRIGGER_TIMER, 0 /*Priority*/);
    
        // Configure steps on sequence.  Sample channels in single-ended mode (default) and configure the interrupt flag after last conversion
        ROM_ADCSequenceStepConfigure(ADC0_BASE, DMA_ADC_SEQUENCER, 0, ADC_CTL_CH0/*PE3*/ | ADC_CTL_IE | ADC_CTL_END);
    
        // Enable ADC Sequence 0 Interrupt on the interrupt controller (NVIC).
        ROM_IntEnable(INT_ADC0SS3);
    
        // This function enables the indicated ADC interrupt sources.  Only the sources that are enabled can be reflected to the processor interrupt;
        // disabled sources have no effect on the processor.
        ROM_ADCIntEnableEx(ADC0_BASE, ADC_INT_DMA_SS3);
    
        // Since ADC0 sample sequence 3 is now configured, it must be enabled.
        ROM_ADCSequenceEnable(ADC0_BASE, DMA_ADC_SEQUENCER);
    
        /////////////////////////////////////////////////
        ////////////// Timer0A Init /////////////////////
    
        // Configure Timer0 to be Periodic
        ROM_TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);
    
        // Load Timer0_A with Sampling Freq. interrupt speed.
        // We do (SamplingFreq. - 1) because the timer fires on zero.
        ROM_TimerLoadSet(TIMER0_BASE, TIMER_A, g_ui32SysClock / (g_uiSamplingFreq - 1));
    
        // Enable Timer 0 to trigger ADC0SS3 when it's load value is met
        TimerControlTrigger(TIMER0_BASE, TIMER_A, true);
    
        // Enable the Timer events that can cause an ADC trigger event.
        TimerADCEventSet(TIMER0_BASE, TIMER_ADC_TIMEOUT_A);
    
        return 1;
    }
    bool DMA_Sample_Start(uint16_t samples)
    {
        if (_sampling)
            return true;
    
        // Initialize the Sample Stop Sequence flag
        g_ui8ADC_DMA_Sample_Stop = 0;
    
        // Reset g_ucDataReady flag so next Main() loop doesn't re-use old ADC data
        g_ucDataReady = 0;
    
        _sampling = true;
    
        // Set samples
        _samples = samples;
    
        // Un-Pend ADC0SS3's Interrupt from the interrupt controller, just in case.
        ROM_IntPendClear(INT_ADC0SS3);
    
        // Load Timer0_A with Sampling Freq. interrupt speed
        ROM_TimerLoadSet(TIMER0_BASE, TIMER_A, g_ui32SysClock / (g_uiSamplingFreq - 1));
    
        // Enable Timer 0 to trigger ADC0SS3 when it's load value is met.
        TimerControlTrigger(TIMER0_BASE, TIMER_A, true);
    
        // Enable the Timer events that can cause an ADC trigger event.
        TimerADCEventSet(TIMER0_BASE, TIMER_ADC_TIMEOUT_A);
    
        ROM_uDMAChannelDisable(UDMA_CH17_ADC0_3);
    
    
        ROM_uDMAChannelTransferSet(UDMA_CH17_ADC0_3 | UDMA_PRI_SELECT,
        UDMA_MODE_PINGPONG,
                                   (void *) (ADC0_BASE + ADC_O_SSFIFO3),
                                   g_ulADCValues_A,
                                   NUM_DMA_TRANSFERS);
        ROM_uDMAChannelTransferSet(UDMA_CH17_ADC0_3 | UDMA_ALT_SELECT,
        UDMA_MODE_PINGPONG,
                                   (void *) (ADC0_BASE + ADC_O_SSFIFO3),
                                   g_ulADCValues_B,
                                   NUM_DMA_TRANSFERS);
    
        // Enable the ADC0 Sequence 3 channel for ADC IN.
        ROM_uDMAChannelEnable(UDMA_CH17_ADC0_3);
    
        // Enable ADC Sequence 0 Interrupt on the interrupt controller (NVIC).
        ROM_IntEnable(INT_ADC0SS3);
    
        // This function enables the indicated ADC interrupt sources.
        // Only the sources that are enabled can be reflected to the processor interrupt;
        // disabled sources have no effect on the processor.
        ROM_ADCIntEnableEx(ADC0_BASE, ADC_INT_DMA_SS3);
    
        // Enables DMA requests to be generated based on the FIFO level of ADC0 sample sequencer 3.
        ADCSequenceDMAEnable(ADC0_BASE, DMA_ADC_SEQUENCER);
    
        // Enable the ADC Sequencer to sample on Timer Trigger
        ROM_ADCSequenceEnable(ADC0_BASE, DMA_ADC_SEQUENCER);
    
        // Enable Timer0_A to sample ADC!!! THIS SHOULD START ADC SAMPLING
        ROM_TimerEnable(TIMER0_BASE, TIMER_A);
    
        return true;
    }
    void ADC3IntHandler(void){
    
        static volatile uint16_t ui16inc = 0; // integrate/decimate counter, we post a new result when ui16inc = 255
        static volatile long accumulatorA=0L; // Heres where we integrate the ADC samples
        static volatile long accumulatorB=0L; // Heres where we integrate the ADC samples
    
        // Accumulator Variables for 'Ping' and 'Pong' Buffers,
        // Is finally copied into g_f32DecimatedArray[]
        volatile uint32_t resultA = 0;
        volatile uint32_t resultB = 0;
    
        ROM_ADCIntClear(ADC0_BASE, DMA_ADC_SEQUENCER);
    
        ADCIntClearEx(ADC0_BASE, ADC_INT_DMA_SS3);
    
        volatile uint32_t ui32Mode;
    
        // Toggle PN_0 LED, Used for verifying Sample Rate via Oscope or Freq.Counter
        //ui8Toggle = !ui8Toggle;
        //ROM_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0, ui8Toggle);
    
        // Grab the mode
        ui32Mode = ROM_uDMAChannelModeGet(UDMA_CH17_ADC0_3 | UDMA_PRI_SELECT);
    
        // We have Data in Ping Buffer
        if (ui32Mode == UDMA_MODE_STOP)
        {
            // We have 256 samples in Ping Buffer, so Accumulate
            for (uint16_t i=0; i<256; i++){
                accumulatorA += g_ulADCValues_A[i];
            }
    
            // Decimate
            resultA = accumulatorA >> 4; // Right-Shift FOUR Virtual Bits to perform the divide operation
    
            // Save Result, increment the g_f32DecimatedArray index
            g_f32DecimatedArray[ui16inc++] = resultA;
    
            // Dump accumulator
            accumulatorA = 0L;
    
            // Setup a new transfer for 'Ping' Buffer
            ROM_uDMAChannelTransferSet(UDMA_CH17_ADC0_3 | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG,
                                       (void *) (ADC0_BASE + ADC_O_SSFIFO3),
                                       g_ulADCValues_A,
                                       NUM_DMA_TRANSFERS);
            // Enable the uDMA Channel
            ROM_uDMAChannelEnable(UDMA_CH17_ADC0_3);
        }
    
        ui32Mode = ROM_uDMAChannelModeGet(UDMA_CH17_ADC0_3 | UDMA_ALT_SELECT);
    
        // We have Data in Pong Buffer
        if (ui32Mode == UDMA_MODE_STOP)
        {
            // We have 256 samples in Pong Buffer, so Accumulate
            for (uint16_t i=0; i<256; i++){
                accumulatorB += g_ulADCValues_B[i];
            }
    
            // Decimate
            resultB = accumulatorB >> 4; // Right-Shift FOUR Virtual Bits to perform the divide operation
    
            // Save Result, increment the g_f32DecimatedArray[] index
            g_f32DecimatedArray[ui16inc++] = resultB;
    
            // Dump accumulator
            accumulatorB = 0L;
    
            // Setup a new transfer for 'Pong' Buffer
            ROM_uDMAChannelTransferSet(UDMA_CH17_ADC0_3 | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG,
                                       (void *) (ADC0_BASE + ADC_O_SSFIFO3),
                                       g_ulADCValues_B,
                                       NUM_DMA_TRANSFERS);
            // Enable the uDMA Channel
            ROM_uDMAChannelEnable(UDMA_CH17_ADC0_3);
        }
    
        // If we've incremented g_f32DecimatedArray[] by our number of samples, stop this handler so we may process data
        if (ui16inc == _samples)
        {
            ROM_TimerDisable(TIMER0_BASE, TIMER_A);
    
            ROM_TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
    
            ROM_IntPendClear(INT_ADC0SS3);
    
            // DISABLE DMA requests from being generated based on the FIFO level of ADC0 sample sequencer 3.
            ROM_ADCSequenceDMADisable(ADC0_BASE, DMA_ADC_SEQUENCER);
    
            // Get the Interrupt Status so we can clear it. Otherwise, we'll end up back in this interrupt handler
            uint32_t ui32ADCIntStatusEx = ROM_ADCIntStatusEx(ADC0_BASE, false); // Not Masked
            ADCIntClearEx(ADC0_BASE, ui32ADCIntStatusEx);
    
            // Reset the DMA Increment count
            ui16inc = 0;
    
            _sampling = 0;
    
            // Signal that we have new data to be processed
            g_ucDataReady = 1;
        }
    
    }

    Please note that this example includes integration and decimation of ADC samples, essentially allowing a finer granularity of ADC resolution (Basically, sample at a greater rate than needed, creating a virtual-resolution for sampled data)

    Feel free to ask away, but this should at the very least get you going. Cheers!

  • There is also a TM4C123 example attached to this post:
    e2e.ti.com/.../2381981