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.

CCS/TM4C123GH6PM: ADC Not Functioning

Part Number: TM4C123GH6PM
Other Parts Discussed in Thread: EK-TM4C123GXL

Tool/software: Code Composer Studio

Hey all! I am trying to figure out the ADC for the Tiva, but I am new to using TivaWare (I am really only familiar with the MSP430).

Anyway, right now my program is getting stuck in the while-loop that waits for the ADC conversion to complete (i.e. while(!ADCIntStatus(ADC0_BASE, 0, false)) {}). It definitely gets stuck there because I have the blue LED toggling before and after the ADC operation, but it never actually toggles the second time.

Also, if you have time please check out the UART part of the code as well. That's priority #2, but it's also not working.

Thanks so much!!!

Please take a look at my code below to see what I'm overlooking:

#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include "driverlib/adc.h"
#include "driverlib/debug.h"
#include "driverlib/fpu.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "inc/hw_adc.h"
#include "inc/hw_gpio.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_sysctl.h"
#include "utils/uartstdio.h"
#include "driverlib/rom.h"

//*****************************************************************************
//
// Configure the ADC and its pins.
//
//*****************************************************************************
void
ConfigureADC(void)
{
    //-----------ADC Setup----------------
    //------------------------------------
    //
    // Enable peripheral ADC0 and reset to apply
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
    SysCtlPeripheralReset(SYSCTL_PERIPH_ADC0);

    //
    // Disable ADC0 sequencer 0 and reconfigure ADC0 sequencer
    //
    ADCSequenceDisable(ADC0_BASE,0);
    ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_PROCESSOR, 0);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_TS /*AIN0*/ | ADC_CTL_IE | ADC_CTL_END);

    //
    // Enable GPIO Port E and set Pin 3 to ADC Type
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3);

    //
    // Enable interrupt for ADC0 SS0
    //
    ADCIntEnable(ADC0_BASE, 0);
}

//*****************************************************************************
//
// Configure the UART and its pins.  This must be called before UARTprintf().
//
//*****************************************************************************
void
ConfigureUART(void)
{
    //-----------UART Setup---------------
    //------------------------------------
    //
    // Enable GPIO and UART 1 Peripherals
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    SysCtlDelay(3);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART1);
    SysCtlDelay(3);

    //
    // Configure GPIO Pins for UART Mode
    //
    GPIOPinConfigure(GPIO_PB1_U1TX);
    GPIOPinTypeUART(GPIO_PORTB_BASE, GPIO_PIN_1);

    //
    // Use the internal 16MHz oscillator as the UART clock source.
    //
    UARTClockSourceSet(UART1_BASE, UART_CLOCK_PIOSC);

    //
    // Initialize UART (port, baud rate, clock source)
    //
    UARTStdioConfig(0, 9600, 16000000);
}


int main(void) {
    uint32_t result;
    volatile char voltage;
    //
    // Clock Setup to 40 MHz
    //
    SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_2);

    ConfigureADC();
    ConfigureUART();

    IntMasterEnable();

    UARTprintf("Hello, world!\n");

    while(1)
    {
            //
            // Turn on the BLUE LED.
            //
            GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2);

            //
            // Delay for a bit.
            //
            SysCtlDelay(SysCtlClockGet() / 10 / 3);

                //---------------ADC-----------------
                //
                // request ADC conversion
                //
                ADCProcessorTrigger(ADC0_BASE, 0);

                //
                // Clear interrupt flag for ADC0 sequencer 3
                //
                ADCIntClear(ADC0_BASE, 0);

                //
                // Wait until the conversion is finished
                //
                while(!ADCIntStatus(ADC0_BASE, 0, false)) {}    // THIS IS WHERE THE PROGRAM FREEZES!!!

                //----------Process the Data---------------
                //
                // Read in the data and convert
                //
                ADCSequenceDataGet(ADC0_BASE, 0, &result);
                voltage = result*0.000805664;

            //
            // Turn off the BLUE LED.
            //
            GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0);

            //
            // Delay for a bit.
            //
            SysCtlDelay(SysCtlClockGet() / 10 / 3);
        }
}

  • Cole Mowrer said:
    Anyway, right now my program is getting stuck in the while-loop that waits for the ADC conversion to complete (i.e. while(!ADCIntStatus(ADC0_BASE, 0, false)) {}).

    The posted code enables the ADC interrupt, via calls to ADCIntEnable() and IntMasterEnable(), but there is no interrupt handler shown in the code. If you haven't installed an interrupt handler then the program will end up in the infinite loop in the IntDefaultHandler() in the CCS supplied tm4c123gh6pm_startup_ccs.c file. After the program has frozen, if you suspend the debugger I expect the program to stuck in the IntDefaultHandler() function.

    The TivaWare_C_Series-2.1.4.178\examples\boards\ek-tm4c123gxl\usb_dev_gamepad\usb_dev_gamepad.c shows ADCIntStatus() can be polled in the main() function without the need to enable the ADC interrupt. i.e. if you remove the calls to ADCIntEnable() and IntMasterEnable() I expect the program will no longer freeze.

    Also, to avoid race conditions the call to ADCIntClear() should be moved to after the loop which waits for ADCIntStatus() to return true, which is line with the code in the usb_dev_gamepad.c example.

  • So I made changes to reflect the gamepad.c example, and I got rid of the ADCIntEnable() and IntMasterEnable() and moved ADCIntClear(). However, now the program is getting stuck in FaultISR().

  • Cole Mowrer said:
    However, now the program is getting stuck in FaultISR().

    When running your code I was able to repeat the problem of it getting stuck in the FaultISR. Using the advice in Diagnosing Software Faults in Stellaris® Microcontrollers found there was a bus-fault accessing address 0x40038000 which is the ADC0 ADC Active Sample Sequencer register. The start of the ConfigureADC() function is:

        //
        // Enable peripheral ADC0 and reset to apply
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
        SysCtlPeripheralReset(SYSCTL_PERIPH_ADC0);
    
        //
        // Disable ADC0 sequencer 0 and reconfigure ADC0 sequencer
        //
        ADCSequenceDisable(ADC0_BASE,0);

    Where the first ADC0 register which is attempted to be accessed by the ADCSequenceDisable() function is the ADC Active Sample Sequencer register at which the bus fault occurred.

    On the Tiva parts the datasheet mentions there may be latency from when a peripheral is enabled or taken out of reset before the peripheral is ready to be accessed. Attempting to access a peripheral before it is ready results in a bus fault. By changing the ConfigureADC function to wait for the ADC0 peripheral to be become ready stopped the program getting stuck in the fault ISR:

        //
        // Enable peripheral ADC0 and reset to apply
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
        while (!SysCtlPeripheralReady (SYSCTL_PERIPH_ADC0))
        {
        }
        SysCtlPeripheralReset(SYSCTL_PERIPH_ADC0);
        while (!SysCtlPeripheralReady (SYSCTL_PERIPH_ADC0))
        {
        }

    Note that the actual latency for a peripheral to become ready is not specified in the datasheet, and so it is difficult to know if a program will encounter the fault. For robustness a while (!SysCtlPeripheralReady()) loop should be be used before the first attempt to access a peripheral.

    Having stopped the program getting stuck in the faultISR found that was then getting stuck waiting for the ADC conversion to finish. Realized that the program was missing a call to ADCSequenceEnable() to enabled the ADC sequencer. Following adding the ADCSequenceEnable(ADC0_BASE, 0) call to ConfigureADC() the program is now running successfully. The complete code is:

    #include <stdio.h>
    #include <stdbool.h>
    #include <stdint.h>
    #include "driverlib/adc.h"
    #include "driverlib/debug.h"
    #include "driverlib/fpu.h"
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/rom.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/uart.h"
    #include "inc/hw_adc.h"
    #include "inc/hw_gpio.h"
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_sysctl.h"
    #include "utils/uartstdio.h"
    #include "driverlib/rom.h"
    
    //*****************************************************************************
    //
    // Configure the ADC and its pins.
    //
    //*****************************************************************************
    void
    ConfigureADC(void)
    {
        //-----------ADC Setup----------------
        //------------------------------------
        //
        // Enable peripheral ADC0 and reset to apply
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
        while (!SysCtlPeripheralReady (SYSCTL_PERIPH_ADC0))
        {
        }
        SysCtlPeripheralReset(SYSCTL_PERIPH_ADC0);
        while (!SysCtlPeripheralReady (SYSCTL_PERIPH_ADC0))
        {
        }
    
        //
        // Disable ADC0 sequencer 0 and reconfigure ADC0 sequencer
        //
        ADCSequenceDisable(ADC0_BASE,0);
        ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_PROCESSOR, 0);
        ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_TS /*AIN0*/ | ADC_CTL_IE | ADC_CTL_END);
    
        //
        // Enable the sequence but do not start it yet.
        //
        ADCSequenceEnable(ADC0_BASE, 0);
    
        //
        // Enable GPIO Port E and set Pin 3 to ADC Type
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
        GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3);
    }
    
    //*****************************************************************************
    //
    // Configure the UART and its pins.  This must be called before UARTprintf().
    //
    //*****************************************************************************
    void
    ConfigureUART(void)
    {
        //-----------UART Setup---------------
        //------------------------------------
        //
        // Enable GPIO and UART 1 Peripherals
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
        SysCtlDelay(3);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_UART1);
        SysCtlDelay(3);
    
        //
        // Configure GPIO Pins for UART Mode
        //
        GPIOPinConfigure(GPIO_PB1_U1TX);
        GPIOPinTypeUART(GPIO_PORTB_BASE, GPIO_PIN_1);
    
        //
        // Use the internal 16MHz oscillator as the UART clock source.
        //
        UARTClockSourceSet(UART1_BASE, UART_CLOCK_PIOSC);
    
        //
        // Initialize UART (port, baud rate, clock source)
        //
        UARTStdioConfig(0, 9600, 16000000);
    }
    
    
    int main(void) {
        uint32_t result;
        volatile float voltage;
        //
        // Clock Setup to 40 MHz
        //
        SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);
    
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
        GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_2);
    
        ConfigureADC();
        ConfigureUART();
    
        UARTprintf("Hello, world!\n");
    
        while(1)
        {
                //
                // Turn on the BLUE LED.
                //
                GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2);
    
                //
                // Delay for a bit.
                //
                SysCtlDelay(SysCtlClockGet() / 10 / 3);
    
                    //---------------ADC-----------------
                    //
                    // request ADC conversion
                    //
                    ADCProcessorTrigger(ADC0_BASE, 0);
    
                    //
                    // Wait until the conversion is finished
                    //
                    while(!ADCIntStatus(ADC0_BASE, 0, false))
                    {
                    }
    
                    //
                    // Clear interrupt flag for ADC0 sequencer 3
                    //
                    ADCIntClear(ADC0_BASE, 0);
    
                    //----------Process the Data---------------
                    //
                    // Read in the data and convert
                    //
                    ADCSequenceDataGet(ADC0_BASE, 0, &result);
                    voltage = result*0.000805664;
    
                //
                // Turn off the BLUE LED.
                //
                GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0);
    
                //
                // Delay for a bit.
                //
                SysCtlDelay(SysCtlClockGet() / 10 / 3);
            }
    }
    

  • Thanks so much! It seems to be working for now...that is until I screw something else up. Haha
  • Chester,

    Above & beyond - once again - great job!    HAD to be noted!    (multiple dragons - arriving in sequence - all neutralized (& superbly described...)

  • Chester,
    Many thanks for the help you provide!!!