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/EK-TM4C123GXL: ADC not reading properly

Part Number: EK-TM4C123GXL

Tool/software: Code Composer Studio

Hello all,

Now, that's a more complex problem I have (I think), I spent hours trying to make ADC work, without success. I'm trying to read 7 values, on pins PE0 through PE4, PB4 and PB5. When I apply 3V3 on all pins, PE0 PE1 PE2 and PE3 are reading 3V3 normally, but the others fluctuate between 3V3 and random values. When I try to read some pin alone, all the pins fluctuate.

What I tried to do:

  • Enable only ADC0, SS0
  • Enable ADC0 and ADC1, both SS1
  • Change the clock source from PIOSC to PLL (configuring to give 16MHz on both)
  • Change TRIGGER_ALWAYS to TRIGGER_TIMER
  • Trigger the ADC at low speed (1Hz)
  • Comment out the ADCReferenceSet()

What I have enabled on my project:

  • TIMER0,1,2,3,4,5
  • WTIMER0,2
  • WTIMER1 as edge capture pins PC6 PC7
  • PWM0, pins PB7 PC5 PE5
  • PWM1, pin PF1
  • OUTPUT Pins PB2 PB3 PD0 PD1 PD2 PD3
  • INPUT Pins PA2 PA3 PA4 PA5
  • UART0 and PA0 PA1
  • HIBERNATE RTC
  • ADC0 Pins PE0 PE1 PE2 PE3
  • ADC1 Pins PE4 PB4 PB5

Here is some sample code I'm using to config ADC:

inline void config_ADC0(void)
{
    MAP_SysCtlPeripheralDisable(SYSCTL_PERIPH_ADC0);
    MAP_SysCtlPeripheralReset(SYSCTL_PERIPH_ADC0);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
    while(!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_ADC0));

    MAP_GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3);

    MAP_ADCReferenceSet(ADC0_BASE, ADC_REF_INT);

    MAP_ADCSequenceConfigure(ADC0_BASE, 1, ADC_TRIGGER_TIMER, 0x00);

    MAP_ADCSequenceStepConfigure(ADC0_BASE, 1, 0, ADC_CTL_CH0 | ADC_CTL_IE);
    MAP_ADCSequenceStepConfigure(ADC0_BASE, 1, 1, ADC_CTL_CH1 | ADC_CTL_IE);
    MAP_ADCSequenceStepConfigure(ADC0_BASE, 1, 2, ADC_CTL_CH2 | ADC_CTL_IE);
    MAP_ADCSequenceStepConfigure(ADC0_BASE, 1, 3, ADC_CTL_CH3 | ADC_CTL_IE | ADC_CTL_END);

    ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL, 25);

    MAP_ADCHardwareOversampleConfigure(ADC0_BASE, 64);

    MAP_ADCSequenceEnable(ADC0_BASE, 1);

    MAP_IntDisable(INT_ADC0SS1);
    MAP_ADCIntDisable(ADC0_BASE, 1);
    MAP_IntPendClear(INT_ADC0SS1);
    MAP_ADCIntClear(ADC0_BASE, 1);

    MAP_IntPrioritySet(INT_ADC0SS1, 0x20);
    MAP_IntEnable(INT_ADC0SS1);
    MAP_ADCIntEnable(ADC0_BASE, 1);
}

inline void config_ADC1(void)
{
    MAP_SysCtlPeripheralDisable(SYSCTL_PERIPH_ADC1);
    MAP_SysCtlPeripheralReset(SYSCTL_PERIPH_ADC1);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC1);
    while(!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_ADC1));

    MAP_GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_4);
    MAP_GPIOPinTypeADC(GPIO_PORTB_BASE, GPIO_PIN_4 | GPIO_PIN_5);

    MAP_ADCReferenceSet(ADC1_BASE, ADC_REF_INT);

    MAP_ADCSequenceConfigure(ADC1_BASE, 1, ADC_TRIGGER_TIMER, 0x00);

    MAP_ADCSequenceStepConfigure(ADC1_BASE, 1, 0, ADC_CTL_CH9 | ADC_CTL_IE);
    MAP_ADCSequenceStepConfigure(ADC1_BASE, 1, 1, ADC_CTL_CH10 | ADC_CTL_IE);
    MAP_ADCSequenceStepConfigure(ADC1_BASE, 1, 2, ADC_CTL_CH11 | ADC_CTL_IE | ADC_CTL_END);

    ADCClockConfigSet(ADC1_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL, 25);

    MAP_ADCHardwareOversampleConfigure(ADC1_BASE, 64);

    MAP_ADCSequenceEnable(ADC1_BASE, 1);

    MAP_IntDisable(INT_ADC1SS1);
    MAP_ADCIntDisable(ADC1_BASE, 1);
    MAP_IntPendClear(INT_ADC1SS1);
    MAP_ADCIntClear(ADC1_BASE, 1);

    MAP_IntPrioritySet(INT_ADC1SS1, 0x20);
    MAP_IntEnable(INT_ADC1SS1);
    MAP_ADCIntEnable(ADC1_BASE, 1);
}

I have no idea what to do next. Suggestions?

Thanks!

  • First a question, how do you have your A/D inputs connected? Do you have a proper nyquist filter?

    Second you have interrupt enable on every single A/D conversion in the sequence. That's almost certainly wrong.

    For troubleshooting I'd also disable the oversampling.

    Robert
  • I'm using the internal 3V3 and GND in the inputs, I don't have a filter, at least it always worked without one in this case (enabling more peripherals would add more noise? I find it hard to believe that would impact so much).

    By saying that I have interrupt enable on every single A/D conversion you mean the always trigger? Because I changed the trigger to timer and used a range of frequencies to test (1-500Hz). I tried with oversampling disabled, it seems that improved a little, but still fluctuating a lot (drops to zero about >20 times in a row and then go to 1500, 1900, some random values and finally 3300).
  • Would it not make great sense to (temporarily) replace your code w/that w/in, "Examples/Peripherals/ADC/"single_ended.c."

    Such "known good code" establishes a baseline - maybe even a proper "model" - for your subsequent attempts.      And - you've exhibited a tendency to "broaden" - and do "everything at once."    The approach of KISS directs that you, "Start with great focus - upon one single task!"     Only when that task has been proven/tested - should you "Add to the Mix."     (i.e. w/your existing (pardon) "jumble" - where could you even begin?)

    As friend Robert notes - for your results to "wander/vary" so greatly - "your" implementation is HIGHLY SUSPECT...

    Tall stack of chips on that "good code" solving your issue...

  • Helder Sales said:
    I'm using the internal 3V3 and GND in the inputs, I don't have a filter, at least it always worked without one in this case (enabling more peripherals would add more noise? I find it hard to believe that would impact so much).

    I have seen that cause an A/D to return readings at either limit on occasion. For proper A/D operation (i.e. to operate consistently within specification) the inputs to the A/D must be filtered to avoid aliased signals. As well that filter must present a low impedance signal to the A/D input. A/Ds are quite high frequency analog devices. The S/H will be something like 1/10 to 1/2 the conversion time which means you need a > 10MHz bandwidth feeding the input and conversely signals in that range will affect the conversion.

    If you are feeding the same 3V3 used for the CPU Vcc you will have noise in that high frequency range.

    As well as the A/D inputs the A/D power supply must similarly be filtered and noise free. If it uses the same power supply as the digital w/o filtering it will also introduce noise into the conversion, especially since for this processor that also acts as the A/D reference.

    TI has some good references on A/D conversion and proper input filters. If you search the Bookshelf tag you will find references to them.

    Helder Sales said:
    By saying that I have interrupt enable on every single A/D conversion you mean the always trigger?

    No, I mean the '| IE' you have appended to every entry in the sequence. As I said that's almost certainly wrong.

    As cb1 suggested it's likely worthwhile to make sure the examples from TI work before proceeding to something more complicated.

    Robert

  • Robert Adsett72 said:
    No, I mean the '| IE' you have appended to every entry in the sequence. As I said that's almost certainly wrong.

    As cb1 suggested it's likely worthwhile to make sure the examples from TI work before proceeding to something more complicated.

    Bingo! That was the problem. I guess I'll need to find some references in other places about that, because the example cb1 suggested only uses 1 input. Thank you.

    cb1_mobile said:

    Such "known good code" establishes a baseline - maybe even a proper "model" - for your subsequent attempts.      And - you've exhibited a tendency to "broaden" - and do "everything at once."    The approach of KISS directs that you, "Start with great focus - upon one single task!"     Only when that task has been proven/tested - should you "Add to the Mix."     (i.e. w/your existing (pardon) "jumble" - where could you even begin?)

    Actually I successfully implemented ADC once, and experimented with different kind of triggers. But how could I know that with more pins that kind of problem might rise? When did I lost focus?

  • My friend - there are many, many ADC examples - presented right here - this forum.
    The forum "Search Box" atop this forum page - opens a "Pandora's Box" of "Highly similar issues AND code examples."      Almost every one of those "examples" employ multiple channels - (that) is how you could have known that more pins should not EACH (invoke) an "IE".

    [EDIT]:  Stop the Presses!    When in doubt - "RTFM."      And the 4C123 manual reveals:    (below a "true copy")

    When configuring a sample sequence, multiple uses of the same input pin within the same sequence are allowed.     In the ADCSSCTLn register, the IEn bits can be set for any combination of samples,
    allowing interrupts to be generated after every sample in the sequence if necessary.

    Thus - the earlier award of "Bingo" flies in the face of the MCU manual - does it not?    

    Now I thought - just like Robert - that, "ONLY one sequence should trigger the interrupt."     And - that method is KNOWN to work.     Yet - the manual clearly states differently!    

    It then must be that your related "Interrupt Handler" is (or was) not properly matched to the individual ADC sequence bombardment!

    As to "focus" - you have "So many aspects of the ADC engaged" (i.e. "oversampling") - that proves "FAR from focused" does it not?       Adding (still) more (unproven) parts to a "failed/failing mix" - does NOT meet the definition of focus.     In addition - just review ALL of the functions (beyond the ADC ones) which are "open-running/enabled" - it is "Never for sure" that a harmful interaction may not - thus result.    Again - breach of focus...

    And - as past stated - that (overload of functions) appears  a strong tendency.      (you may note that I've long been engaged - at extraordinary rates - to make such critical observations.)      Thus may prove to your advantage to "accept the observation" - and comply - and note if improvement results.          (another "simple hint" - it WILL!)