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.

TM4C129ENCPDT: Read multiple pins ADC0

Part Number: TM4C129ENCPDT

Hi all,

I'm trying to read analog values in multiple pins with tm4c129, but I'm getting always zero.

Can I get some help, please?

My code is attached.

/*
 * adc.c
 *
 *  Created on: 6 de set de 2017
 *      Author: allefpablo
 */
#include <stdarg.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include "inc/hw_adc.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "driverlib/debug.h"
#include "driverlib/gpio.h"
#include "driverlib/sysctl.h"
#include "driverlib/interrupt.h"
#include "driverlib/adc.h"
#include "driverlib/pin_map.h"

#include "board_drivers/hardware_def.h"
#include "adc.h"

static uint32_t pui32ADC0Value[11];

void adc_init()
{
    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);

    //
    // Select the analog ADC function for these pins.
    // Consult the data sheet to see which functions are allocated per pin.
    // TODO: change this to select the port/pin you are using.
    //
    GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_0);
    GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_1);
    GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_2);
    GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_3);
    GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_4);
    GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_5);
    GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_6);
    GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_7);

    GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_0);
    GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_1);
    GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_2);

    //
    // Enable sample sequence 3 with a processor signal trigger.  Sequence 3
    // will do a single sample when the processor sends a signal to start the
    // conversion.  Each ADC module has 4 programmable sequences, sequence 0
    // to sequence 3.  This example is arbitrarily using sequence 3.
    //
    //ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_PROCESSOR, 0);

    //
    // Configure step 0 on sequence 3.  Sample channel 0 (ADC_CTL_CH0) in
    // single-ended mode (default) and configure the interrupt flag
    // (ADC_CTL_IE) to be set when the sample is done.  Tell the ADC logic
    // that this is the last conversion on sequence 3 (ADC_CTL_END).  Sequence
    // 3 has only one programmable step.  Sequence 1 and 2 have 4 steps, and
    // sequence 0 has 8 programmable steps.  Since we are only doing a single
    // conversion using sequence 3 we will only configure step 0.  For more
    // information on the ADC sequences and steps, reference the datasheet.
    //
    ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH1);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 1, ADC_CTL_CH2);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 2, ADC_CTL_CH3);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 3, ADC_CTL_CH4);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 4, ADC_CTL_CH5);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 5, ADC_CTL_CH6);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 6, ADC_CTL_CH7);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 7, ADC_CTL_CH12);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 8, ADC_CTL_CH13);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 9, ADC_CTL_CH14);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 10, ADC_CTL_CH15 | ADC_CTL_IE |
                             ADC_CTL_END);

    IntEnable(INT_ADC0SS0);
    //
    // Since sample sequence 3 is now configured, it must be enabled.
    //
    ADCSequenceEnable(ADC0_BASE, 0);
    ADCSequenceEnable(ADC0_BASE, 1);
    ADCSequenceEnable(ADC0_BASE, 2);
    ADCSequenceEnable(ADC0_BASE, 3);
    ADCSequenceEnable(ADC0_BASE, 4);
    ADCSequenceEnable(ADC0_BASE, 5);
    ADCSequenceEnable(ADC0_BASE, 6);
    ADCSequenceEnable(ADC0_BASE, 7);
    ADCSequenceEnable(ADC0_BASE, 8);
    ADCSequenceEnable(ADC0_BASE, 9);
    ADCSequenceEnable(ADC0_BASE, 10);

    //
    // Clear the interrupt status flag.  This is done to make sure the
    // interrupt flag is cleared before we sample.
    //
    //ADCIntClear(ADC0_BASE, 0);
}


uint32_t read_adc(uint32_t sequence, uint32_t *values)
{
    ADCIntClear(ADC0_BASE, sequence);
    ADCProcessorTrigger(ADC0_BASE, sequence);
    while(!ADCIntStatus(ADC0_BASE, sequence, false)){}
    return (ADCSequenceDataGet(ADC0_BASE, sequence, values));
}

uint32_t get_voltage_ch_1()
{
    return read_adc(4, pui32ADC0Value);
}

uint32_t get_voltage_ch_2()

{
    return read_adc(3, pui32ADC0Value);
}

uint32_t get_voltage_ch_3()
{
    return read_adc(5, pui32ADC0Value);
}

uint32_t get_voltage_ch_4()
{
    return read_adc(6, pui32ADC0Value);
}

uint32_t get_current_ch_1()
{
    return read_adc(2, pui32ADC0Value);
}

uint32_t get_current_ch_2()
{
    return read_adc(1, pui32ADC0Value);
}

uint32_t get_current_ch_3()
{
    return read_adc(0, pui32ADC0Value);
}

uint32_t get_current_ch_4()
{
    return read_adc(7, pui32ADC0Value);
}

uint32_t get_lv_signal_ch_1()
{
    return read_adc(8, pui32ADC0Value);
}

uint32_t get_lv_signal_ch_2()
{
    return read_adc(9, pui32ADC0Value);
}

uint32_t get_lv_signal_ch_3()
{
    return read_adc(10, pui32ADC0Value);
}

  • Hello Allef,

    I would suggest you take a step back and instead get to a point where you are getting a single ADC to work correctly.

    Please start with TI Example Code provided with TivaWare which can be found at [Install Path]\TivaWare_C_Series-2.1.4.178\examples\peripherals\adc

    Using this code, setup a single ADC pin/channel and work towards getting a single reading that is correct. Once you have accomplished this, then you can expand to using multiple pins from there.

    If you are having issues getting a singular reading with the TI example code, please report back including what steps you have taken in modifying the example code, what challenges you are facing, and providing full source code (including the main() function and any initialization for the device).
  • Agree w/vendor's prescription of, "Simplicity" and following the (known good) example code.     (Such simplicity may be better conveyed via the always memorable, "KISS" (never employed by vendor agents) - thus (repeatedly) poster issues are "most always" due to needless complexity!)

    Poster has either missed, misunderstood or not properly followed "SW_TM4C-DRL-UG-2" (Peripheral Driver User Guide.)     His use of ADC functions - while "original" - are (often) not in compliance w/these API functions.     Specifically:

    • Posters (essentially commented out preamble narrative) "seems" to indicate the selection of "Sequence 3."   (which yields a single conversion via one step)    

    Poster code however:    ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH1);    has in fact selected Sequence 0.    (which yields up to 8 stepped conversions)

    • Yet that's the, "tip of the iceberg" - poster's code attempts to install ELEVEN steps w/in Sequence 0!     (again - 8 is the maximum allowed)
    • Poster's code does enable ADC0 - yet shows NO enabling of (either) of his chosen (ADC encompassing) Ports - "D & E."    (if that code is "elsewhere" - how are we "helpers" to guide/advise?)
    • Poster's code continues - and enables Sequences 0 - 10.    His commented out code preamble (instruction) states (only) Sequence 0-3 are valid.
    • The variable "sequence" is employed in at least 3 function calls - yet is nowhere defined.
    • Poster's code describes, "Each/Every pin w/in Port D as being ADC capable!"    (while that (may) be true - has poster REALLY confirmed?)   Not ALL MCU pins may serve as ADC - MCU manual details.

    The example code, "Single_Ended.C" (found examples/peripherals) is long proven - illustrates the proper function order.    Used in conjunction w/the Peripheral Driver User Guide (above) a solid "Roadmap" for the appropriate ADC related functions is effectively provided...  

    To save (others) and this poster (time/effort) I present key segments (unmodified) of his "adc.c" code:   (these illustrate & document my findings)

    {
    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);

    //
    // Select the analog ADC function for these pins.
    // Consult the data sheet to see which functions are allocated per pin.
    // TODO: change this to select the port/pin you are using.
    //
    GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_0);
    GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_1);
    GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_2);
    GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_3);
    GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_4);
    GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_5);
    GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_6);
    GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_7);

    GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_0);
    GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_1);
    GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_2);

    ***

    ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH1);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 1, ADC_CTL_CH2);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 2, ADC_CTL_CH3);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 3, ADC_CTL_CH4);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 4, ADC_CTL_CH5);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 5, ADC_CTL_CH6);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 6, ADC_CTL_CH7);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 7, ADC_CTL_CH12);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 8, ADC_CTL_CH13);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 9, ADC_CTL_CH14);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 10, ADC_CTL_CH15 | ADC_CTL_IE |
    ADC_CTL_END);

    ***

    IntEnable(INT_ADC0SS0);
    //
    // Since sample sequence 3 is now configured, it must be enabled.
    //
    ADCSequenceEnable(ADC0_BASE, 0);
    ADCSequenceEnable(ADC0_BASE, 1);
    ADCSequenceEnable(ADC0_BASE, 2);
    ADCSequenceEnable(ADC0_BASE, 3);
    ADCSequenceEnable(ADC0_BASE, 4);
    ADCSequenceEnable(ADC0_BASE, 5);
    ADCSequenceEnable(ADC0_BASE, 6);
    ADCSequenceEnable(ADC0_BASE, 7);
    ADCSequenceEnable(ADC0_BASE, 8);
    ADCSequenceEnable(ADC0_BASE, 9);
    ADCSequenceEnable(ADC0_BASE, 10);

    ***

    uint32_t read_adc(uint32_t sequence, uint32_t *values)
    {
    ADCIntClear(ADC0_BASE, sequence);
    ADCProcessorTrigger(ADC0_BASE, sequence);
    while(!ADCIntStatus(ADC0_BASE, sequence, false)){}
    return (ADCSequenceDataGet(ADC0_BASE, sequence, values));
    }

  • Hi all,

    I can see a lot of mistakes now. I went back a few steps and could make it work.

    Here is the new code.

    /*
     * adc.c
     *
     *  Created on: 6 de set de 2017
     *      Author: allefpablo
     */
    
    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_memmap.h"
    #include "driverlib/adc.h"
    #include "driverlib/gpio.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/sysctl.h"
    
    #include "adc.h"
    
    static uint32_t adc_voltage_value[7];
    static uint32_t adc_current_value[4];
    
    void adc_init()
    {
        //
        // Enable ADC0 and ADC1
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC1);
    
        //
        // Select the analog ADC function for these pins.
        //
        GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 |
                                        GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
        GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2);
    
    
        //
        // Enable sample sequence 0 (Max 8 samples) for ADC0 and
        // enable sample sequence 1 (Max 4 samples) for ADC1
        // Both with a processor trigger signal
        //
        ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_PROCESSOR, 0);
        ADCSequenceConfigure(ADC1_BASE, 1, ADC_TRIGGER_PROCESSOR, 0);
    
        //
        // Configure steps on sequence 0 and 1. Here, we are using 7 channels
        // for ADC0 and 4 channels for ADC1
        //
        ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH5);
        ADCSequenceStepConfigure(ADC0_BASE, 0, 1, ADC_CTL_CH4);
        ADCSequenceStepConfigure(ADC0_BASE, 0, 2, ADC_CTL_CH6);
        ADCSequenceStepConfigure(ADC0_BASE, 0, 3, ADC_CTL_CH7);
        ADCSequenceStepConfigure(ADC0_BASE, 0, 4, ADC_CTL_CH13);
        ADCSequenceStepConfigure(ADC0_BASE, 0, 5, ADC_CTL_CH14);
        ADCSequenceStepConfigure(ADC0_BASE, 0, 6, ADC_CTL_CH15 | ADC_CTL_IE |
                                 ADC_CTL_END);
        ADCSequenceStepConfigure(ADC1_BASE, 1, 0, ADC_CTL_CH3);
        ADCSequenceStepConfigure(ADC1_BASE, 1, 1, ADC_CTL_CH2);
        ADCSequenceStepConfigure(ADC1_BASE, 1, 2, ADC_CTL_CH1);
        ADCSequenceStepConfigure(ADC1_BASE, 1, 3, ADC_CTL_CH12 | ADC_CTL_IE |
                                 ADC_CTL_END);
    
        //
        // Enable sample sequences.
        //
        ADCSequenceEnable(ADC0_BASE, 0);
        ADCSequenceEnable(ADC1_BASE, 1);
    
        //
        // Clear the interrupt status flag.  This is done to make sure the
        // interrupt flag is cleared before we sample.
        //
        ADCIntClear(ADC0_BASE, 0);
        ADCIntClear(ADC1_BASE, 1);
    }
    
    
    void read_adc_0()
    {
        //
        // Trigger the ADC0 conversion.
        //
        ADCProcessorTrigger(ADC0_BASE, 0);
        //
        // Wait for conversion to be completed.
        //
        while(!ADCIntStatus(ADC0_BASE, 0, false)){}
        //
        // Clear the ADC interrupt flag.
        //
        ADCIntClear(ADC0_BASE, 0);
        //
        // Read ADC Value.
        //
        ADCSequenceDataGet(ADC0_BASE, 0, adc_voltage_value);
        //
        // Wait.
        //
        SysCtlDelay(1000);
    }
    
    void read_adc_1()
    {
        //
        // Trigger the ADC1 conversion.
        //
        ADCProcessorTrigger(ADC1_BASE, 1);
        //
        // Wait for conversion to be completed.
        //
        while(!ADCIntStatus(ADC1_BASE, 1, false)){}
        //
        // Clear the ADC interrupt flag.
        //
        ADCIntClear(ADC1_BASE, 1);
        //
        // Read ADC Value.
        //
        ADCSequenceDataGet(ADC1_BASE, 1, adc_current_value);
        //
        // Wait.
        //
        SysCtlDelay(1000);
    }
    
    uint32_t get_voltage_ch_1()
    {
        read_adc_0();
        return adc_voltage_value[0];
    }
    
    uint32_t get_voltage_ch_2()
    {
        read_adc_0();
        return adc_voltage_value[1];
    }
    
    uint32_t get_voltage_ch_3()
    {
        read_adc_0();
        return adc_voltage_value[2];
    }
    
    uint32_t get_voltage_ch_4()
    {
        read_adc_0();
        return adc_voltage_value[3];
    }
    
    uint32_t get_lv_signal_ch_1()
    {
        read_adc_0();
        return adc_voltage_value[4];
    }
    
    uint32_t get_lv_signal_ch_2()
    {
        read_adc_0();
        return adc_voltage_value[5];
    }
    
    uint32_t get_lv_signal_ch_3()
    {
        read_adc_0();
        return adc_voltage_value[6];
    }
    
    uint32_t get_current_ch_1()
    {
        read_adc_1();
        return adc_current_value[0];
    }
    
    uint32_t get_current_ch_2()
    {
        read_adc_1();
        return adc_current_value[1];
    }
    
    uint32_t get_current_ch_3()
    {
        read_adc_1();
        return adc_current_value[2];
    }
    
    uint32_t get_current_ch_4()
    {
        read_adc_1();
        return adc_current_value[3];
    }
    
    

    Thanks!

  • Wow - that was FAST! Good for you.

    The API IS powerful - yet demands "attention to detail" - which appears you've (now) supplied.
    Your "original" attempt was "logical" - yet did not comply w/the API's requirement for (strict) compliance.

    Might you reward my (detailed) issue identification w/the "Answer Succeeded" (green button click - upon my first post?) Thank you.