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.

TM4C1294NCPDT: ADC sequencer error

Part Number: TM4C1294NCPDT

Hi,

I am using an ADC sequencer to monitor 7 power supply voltages on my board.

This is the code that initialises the ADC and its sequencer.

    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
    while(!(SysCtlPeripheralReady(SYSCTL_PERIPH_ADC0)));    //wait for peripheral ready

    MAP_GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_0);    //1V
    MAP_GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_1);    //1.2V
    MAP_GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_2);    //1.5V
    MAP_GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_3);    //1.8V
    MAP_GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_4);    //2.5V
    MAP_GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_5);    //3.3V via div2 resistors
    MAP_GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_6);    //5V via div2 resistors

    ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PIOSC | ADC_CLOCK_RATE_FULL, 1);            //clock for both adcs

    ADCReferenceSet(ADC0_BASE, ADC_REF_INT);                  //VDDA = 3.3V
    ADCSequenceDisable(ADC0_BASE, 0);                                                    //disable sequence before we change it
    ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_PROCESSOR, 0);                        //select processor (software) trigger
    ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH15);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 1, ADC_CTL_CH14);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 2, ADC_CTL_CH13);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 3, ADC_CTL_CH12);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 4, ADC_CTL_CH7);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 5, ADC_CTL_CH6);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 6, ADC_CTL_CH5);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 7, ADC_CTL_CH5 | ADC_CTL_END);
    ADCIntClear(ADC0_BASE, 0);                                                            //clear the interrupt status flag
    ADCSequenceEnable(ADC0_BASE, 0);                                                    //enable sequence

The sequencer is triggered in the application once a second like this...

uint32_t ADC0_raw[8];

    ADCProcessorTrigger(ADC0_BASE, 0);                //trigger
    while(ADCIntStatus(ADC0_BASE, 0, false))        //wait complete
    {
    }
    ADCIntClear(ADC0_BASE, 0);                        //clear the ADC interrupt flag
    ADCSequenceDataGet(ADC0_BASE, 0, ADC0_raw);        //read ADC values

Most of the time this works very well.

However occasionally the sequence gets the channels wrong and channel 0 gets channel 1 input, channel 1 gets channel 2 etc. I can see this happening in the debugger. Once it is in this state it stays this way until reset (I think). This of course renders the supply monitoring totally useless!

Has anyone come across this problem and is there a fix or workaround?

Thanks,

Richard

  • Hello Richard

    In the code post, I see that there are 7 ADC pins but the Sequencer has been configured for 8 steps. Is this the intended implementation that you had planned?
  • Hi Amit,
    I only have 7 voltages to read so the 8th sequencer sample reads the last channel again.
    I was under the impression that SS0 is fixed at 8 samples. Can I set it to be 7?
    Also, can I reset the sequencer, perhaps with disable/enable?
    Regards
    Richard
  • Ah I have just read about setting the END bit at the last sample, thereby making it a 7 sample sequence.
    I will try this. Doesn't explain the problem though.
    Richard
  • Hello Richard

    Make sure that the ADC is reset at every rerun by adding the following code

    SysCtlPeripheralDisable(SYSCTL_PERIPH_ADC0);
    SysCtlPeripheralReset(SYSCTL_PERIPH_ADC0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
    while(!(SysCtlPeripheralReady(SYSCTL_PERIPH_ADC0))); //wait for peripheral ready

    Also ensure that the ADC register space is not open in a memory or register browser.
  • Hi Amit,

    Putting the END bit at the 7th sample makes the problem much worse - the sequence gets out of step very quickly.

    Is it normal to reset the ADC before each sequence or are you just suggesting I do this to see if it helps?

    Richard
  • Hello Richard

    It is a good practice to reset a module during development as some users perform CPU reset which does not reset the peripheral.

    Also did you make sure that the ADC registers are not open in the register or memory window!
  • It seems resetting the ADC also resets the sequence to not programmed.

    This is the same project that I had so much trouble with the sequencer that is measuring the temperature (on a post in the RTOS forum - not answered) where it turned out that a 4 step sequencer would sometime return 8 values (running off the end of my array and causing a crash) simply extending the array to 8 values prevented the crash.

    Why am I having so much trouble with these sequencers? I wonder if there's a clue....
  • Richard Bland said:
    occasionally sequencer gets the channels wrong - chan 0 gets chan 1, chan 1 gets chan 2 etc. I can see this happening in the debugger.

    Amit has advised - and we (too) have noted - that the debugger "open to the ADC Registers" may negatively impact!

    To be safe - our method was to "copy each ADC sequence reading to a safe variable which we display in IAR's Quick View.

  • Hello Richard

    The steps mentioned need to be done only once before the ADC is configured. It does not need to be done multiple time in the application code.
  • Yes indeed, the only debugger window open is "Expressions" where I am displaying my arrays ADC0_raw[] where ADCSequenceDataGet(ADC0_BASE, 0, ADC0_raw) places its results an an array called volts[] which is ADC-raw converted into volts.

    I understand you suggest I put peripheral reset in the init code - thanks I usually do that - will add it.

    Thank you
    Richard
  • Hello Richard

    In the last step of the sequence why is not the IE condition set

    ADCSequenceStepConfigure(ADC0_BASE, 0, 7, ADC_CTL_CH5 | ADC_CTL_END);

    should be

    ADCSequenceStepConfigure(ADC0_BASE, 0, 7, ADC_CTL_CH5 | ADC_CTL_IE | ADC_CTL_END);
  • Hi Amit,

    Maybe you have hit apon the issue here.


    Tiva running "native" using Tivaware...

    From the Tivaware TivaRomUG, ROM_ADCSequenceStepConfigure.... it can be configured to cause an interrupt when the step is complete (the ADC_CTL_IE bit).

    I don't want it to cause an interrupt, and I have not written any interrupt code nor registered the ISR in the startup code. However I find that if I do not set ADC_CTL_IE, the code gets stuck at "while(ADCIntStatus(ADC0_BASE, 0, false)) ;". So I set ADC_CTL_IE which doesn't generate an interrupt, but it does allow the "while(..)" to finish.

    I conclude from this that the wording is wrong in the UG. Rather than "cause an interrupt" it should read "sets the interrupt flag" (which is masked), and the "while(..)" is watching for the flag to be set.


    IMPORTANT: Tiva running under RTOS...

    Now the project in question in this thread is running under RTOS. There does not appear to be support for the ADC within RTOS, so I am still using the same Tivaware functions.

    The difference is that if I set ADC_CTL_IE I get an immediate exception fault. Leaving ADC_CTL_IE not set seems to fix the problem but I am getting trouble with the sequencers. Indeed if I set the ADC_CTL_END bit at the 6th step (instead of the 7th last) the sequence gets the wrong channels every other time it is run. What have I misunderstood here?

    Thanks
    Richard
  • I am fairly sure that the problem is that the line "while(ADCIntStatus(ADC0_BASE, 0, false)) ;" falls straight through and my code is reading the sequence fifo before it is ready.

    If I put a "Task_sleep(1)" after the "while(..)" all works fine it seems.

    Maybe this has been my problem all along? Could this have caused the sequencer to return too many values as in my temperature reading problem (which cost many days of development time and hair-loss!). See e2e.ti.com/.../1994081

    It really is time for TI to put ADC support into RTOS as so many posts indicate difficulties here. (Please please).

    Richard
  • Hello Richard,

    The ADC_CTL_IE setting allows the sequencer to generate an interrupt condition. It is the Interrupt mask bit which propagates it to the NVIC. So I believe the statement is correct.
  • Hi Amit,
    Do I assume that the ADC interrupt is unmasked by default in RTOS and this is what generates the exception?
    If so what is the right command to mask it?
    And do I assume the while(..) drops straight through because the interrupt flag is not cleared by ADCIntClear(ADC0_BASE, 0);
    If so why isn't it? Or what sets at the wrong time?
    Has anybody successfully used the ADC within RTOS? If so could they post how they did it please!
    Richard
  • Hello Richard

    Unfortunately, I am not a RTOS person, and scares me to use something that i do not have a full control over.

    Yes, I believe the interrupt flag not being cleared will cause the CPU to go through.
  • Hi Amit,

    It scares me too!
    It's really great when it works, but a nightmare to debug when it doesn't.
    I'm using it because, in tests, it was faster at handling ethernet TCP than my handwritten lwip version was.

    I should re-post the question on the RTOS forum I think.

    Thanks for all your help by the way, very much appreciated.
    Best regards - and Happy New Year!
    Richard
  • Now I feel really foolish!
    The whole issue was because I missed out the "!" in the while statement, so yes, it was dropping straight though!
    Duh!
    Once again apologies for wasting your time.
    Best regards,
    Richard
  • Hello Richard

    Missed us by a mile too. Glad you saw it and updated the same on the forum.