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 feedback not working properly after processor change

Part Number: TM4C1294NCPDT
Other Parts Discussed in Thread: TM4C129XNCZAD,

Tool/software:

Hi, 

We recently updated our embedded microcontroller from the tm4c129xnczad to the TM4C1294NCPDT. 

The ADC setup method (c++) was : 

(tm4c129xnczad )

SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
SysCtlADCSpeedSet(SYSCTL_ADCSPEED_125KSPS); 

ADCSequenceDisable(ADC0_BASE, 0);

ADCHardwareOversampleConfigure(ADC0_BASE, 64);

ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_PROCESSOR, 0);

ADCSequenceStepConfigure(ADC0_BASE, 0, 0,
ADC_CTL_CH0 | ADC_CTL_IE);
adc = new TivaWareIntegratedADCDriver(ADC0_BASE, 0, 0);
((TivaWareIntegratedADCDriver*) adc)->setSharedBuffer(*adcSharedBuffer);

...

ADCIntEnable(ADC0_BASE, 0);
ADCSequenceEnable(ADC0_BASE, 0);

and worked fine. 

After the processor driver update the macro SysCtlADCSpeedSet is not available anymore so the code that replace it looks like this:

(TM4C1294NCPDT)

ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_EIGHTH, 64); 

The problem is that the adc feedback is not accurate. In idle state all the adc feedbacks goes from 1 to 1353 every second.

Is the code for the new processor correct in the ADC setup?  Is there an other way to do this?

This is the complete method for the new microcontroller:

SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_EIGHTH, 64);

ADCSequenceDisable(ADC0_BASE, 0);

ADCHardwareOversampleConfigure(ADC0_BASE, 64);

ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_PROCESSOR, 0);

ADCSequenceStepConfigure(ADC0_BASE, 0, 0,
ADC_CTL_CH0 | ADC_CTL_IE);
adc= new TivaWareIntegratedADCDriver(ADC0_BASE, 0, 0);
((TivaWareIntegratedADCDriver*) adc)->setSharedBuffer(*adcSharedBuffer);

...

ADCIntEnable(ADC0_BASE, 0);
ADCSequenceEnable(ADC0_BASE, 0);

  • ADCSequenceStepConfigure(ADC0_BASE, 0, 0,
    ADC_CTL_CH0 | ADC_CTL_IE);
    adc = new TivaWareIntegratedADCDriver(ADC0_BASE, 0, 0);
    ((TivaWareIntegratedADCDriver*) adc)->setSharedBuffer(*adcSharedBuffer);

    ...

    Hi,

      In your code for tm4c129xnczad, I'm actually surprised that it works without ADC_CTL_END. I would have expected. 

    ADCSequenceStepConfigure(ADC0_BASE, 0, 0,
    ADC_CTL_CH0 | ADC_CTL_IE | ADC_CTL_END ); // ADC_CTL_END indicates ADC_CTL_CH0 is the last channel in the group for Sequence Compare 0. 

    After the processor driver update the macro SysCtlADCSpeedSet is not available anymore so the code that replace it looks like this:

    You must be using a extremely old TivaWare or carry over code from LM3S. There is no SysCtlADCSpeedSet API in  later versions of TivaWare Peripheral Driver Library, It is replaced with ADCClockConfigSet.  Please refer to the latest Peripheral Driver Library User's Guide for this API. 

    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
    ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_EIGHTH, 64);

    To achieve 1Msps, you would need to run the ADC clock at 16Mhz. Therefore, to achieve 1Msps you would need to divide the PLL VCO (240Mhz) by 15 for the ADC clock to be 16Mhz. To get 125KSPS you will use ADC_CLOCK_RATE_EIGHTH. So try something like below. 

    ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_EIGHTH, 15);

    Also make sure you add ADC_CTL_END as mentioned above. 

  • Hi,

    i tried this: 

    ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_EIGHTH, 15);

    but it didn't  work correctly, 

    The problem is that the adc feedback is not accurate. In idle state all the adc feedbacks goes from 1 to 1353 every second.

    this still happens at 16Mhz. One of the adc feedback is (correctly) returning the feedback 1300 circa. The problem is that the buffer is "cycling" so the 

    value goes from the first adc feedback to the last adc passing by every feedback. 

    I tried at 30 Mhz dividing 240 by 8 and this seems to work. 

    however i was told that this much speed is kind of wasted because of the smaller amount of operations needed and also it could raise the 

    temperature of the micro controller. 

    How can i reduce the sampling speed? or is it a problem to lt the adc go at this speed?

    the code i am using is this: ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_EIGHTH, 8);

    with the previous chip the speed was in fact 125ksps, how can i get this value?

  • i tried this: 

    ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_EIGHTH, 15);

    but it didn't  work correctly, 

    Can you elaborate this sampling rate you are achieving for this configuration?

    this still happens at 16Mhz. One of the adc feedback is (correctly) returning the feedback 1300 circa. The problem is that the buffer is "cycling" so the 

    value goes from the first adc feedback to the last adc passing by every feedback. 

    What do you mean by feedback? Do you mean the adc value that you read is not correct? You are expecting to read 1300 but instead you read 1?

    I tried at 30 Mhz dividing 240 by 8 and this seems to work. 

    Can you show the parameters you set up for ADCClockConfigSet that works?

    How can i reduce the sampling speed? or is it a problem to lt the adc go at this speed?

    the code i am using is this: ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_EIGHTH, 8);

    with the previous chip the speed was in fact 125ksps, how can i get this value?

    What sampling rate are you achieving here with ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_EIGHTH, 8);?

  • Can you elaborate this sampling rate you are achieving for this configuration?

    We used 125ksps with the old processor ADCs. I was told that 1 Msps is much more than needed and could raise the temperature of the board. Now i am using 240/8=30Mhz so it's even more, but i couldn't find a way to use a smaller amount of sample per second rate. 

    What do you mean by feedback? Do you mean the adc value that you read is not correct?

    The problem i encountered is this: i have 6 adcs channels to use. one of this is returning 1300 and that's correct, the others should stay at 0. But when the sample rate is higher or lower than 30Mhz this happens: 

    i have a software which help me to see what is the current feedback of the adc channels. every feedback value is in one panel so i can see every value togheter. that 1300 feedback should stay only in one of them but i can see it going from the first to the last like if it is cycling. so let's say this array contains the 6 values of the buffer: 0 0 1300 0 0 0, every 50 ms (circa) i see this happening: 0 0 0 1300 0 0 and then 0 0 0 0 1300 0 and so on. This is what i meant for cycling. 

    Can you show the parameters you set up for ADCClockConfigSet that works?

    this is the current clock config configuration i am using:

    ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_EIGHTH, 8);

    What sampling rate are you achieving here with ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_EIGHTH, 8);?

    Since the last method parameter is the divisor, i guess the sampling rate i am getting is 240Mhz / 8 = 30Mhz, am i right? 

    Could the problem be related to the adc buffer in the software? this is the driver i am currently using:

    #include "adcdriver/TivaWareIntegratedADCDriver.h"

    TivaWareIntegratedADCDriver::TivaWareIntegratedADCDriver(uint32_t base,
    uint32_t sequenceNum, uint32_t step)
    : AbstractADCDriver(),
    base(base),
    sequenceNum(sequenceNum),
    value(0),
    step(step)
    {
    buffer = new uint32_t[8];
    }

    TivaWareIntegratedADCDriver::~TivaWareIntegratedADCDriver()
    {
    // TODO Auto-generated destructor stub
    }

    double TivaWareIntegratedADCDriver::read() {
    // ADCProcessorTrigger(base, sequenceNum);
    // while(!ADCIntStatus(ADC0_BASE, sequenceNum, false)){}
    // uint32_t size = ADCSequenceDataGet(base, sequenceNum, buffer);
    value = static_cast<double>(buffer[step]);
    return value;
    }

    void TivaWareIntegratedADCDriver::updateADC() {
    ADCProcessorTrigger(base, sequenceNum);
    while(!ADCIntStatus(ADC0_BASE, sequenceNum, false)){}
    uint32_t size = ADCSequenceDataGet(base, sequenceNum, buffer);
    }

    void TivaWareIntegratedADCDriver::setSharedBuffer(uint32_t& buffer) {
    this->buffer=&buffer;
    }

  • Now i am using 240/8=30Mhz so it's even more, but i couldn't find a way to use a smaller amount of sample per second rate. 

    Hi,

      Have you tried ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_EIGHTH, 15) as I suggested before. 240/15=16Mhz. 16Mhz would have given you a maximum of 1Msps. If you additionally apply ADC_CLOCK_RATE_EIGHTH then it will give you 1Msps / 8 = 125Ksps. This was the question I was trying to ask you what actual sample rate did you obtain when you divide by 15. 

    so let's say this array contains the 6 values of the buffer: 0 0 1300 0 0 0, every 50 ms (circa) i see this happening: 0 0 0 1300 0 0 and then 0 0 0 0 1300 0 and so on. This is what i meant for cycling. 

    Are you reading the array in an ADC ISR? In your code, you use ADC_CTL_IE. With this flag, it will generate ADC interrupt when the last channel in the Sample Sequencer completes its conversion. 

    Here you said you are reading the buffer every 50ms. Are you using a timer to generate this 50ms period? Are you reading the buffer inside a timer ISR at 50ms rate? 

    It seems like while you are reading the ADC FIFO using ADCSequenceDataGet, there may be another channel conversion completed with its value pushed to the FIFO.  

    Can you check ADCOSTAT and ADCUSTAT registers to see if you have any FIFO Overflow or Underflow events?

    Since the last method parameter is the divisor, i guess the sampling rate i am getting is 240Mhz / 8 = 30Mhz, am i right? 

    Could the problem be related to the adc buffer in the software? this is the driver i am currently using:

    240 / 8 = 30Mhz which would have given you a max of 2Msps. This is why I asked to divide by 15 to get 16Mhz.  

  • Hi, 

    sorry i am new to this kind of programming, i am used to high level code like c#. 

    Are you using a timer to generate this 50ms period? Are you reading the buffer inside a timer ISR at 50ms rate? 

    im am not using any timers, i was just saying it refreshes very fast

    Have you tried ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_EIGHTH, 15) as I suggested before. 240/15=16Mhz. 16Mhz would have given you a maximum of 1Msps. If you additionally apply ADC_CLOCK_RATE_EIGHTH then it will give you 1Msps / 8 = 125Ksps.

    how can i apply ADC_CLOCK_RATE_EIGHTH a second time?

    Can you check ADCOSTAT and ADCUSTAT registers to see if you have any FIFO Overflow or Underflow events?

    how can i check those registers?

  • i tried this command:

    ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_RATE_FULL, 120); 

    is the full rate 240 Mhz or 480? anyway i am dividing by 120 so it should be around 2 or 4 Mhz and does that mean i am getting 125Ksps or 250Ksps, am i right?

    I guessed that if 16Mhz correspond to 1 Msps, 1Msps/8 = 125Ksps and so 16Mhz/8 = 2Mhz, correct?

  • im am not using any timers, i was just saying it refreshes very fast

    Can you explain how you are reading the ADC? Are you using the interrupt and reading the ADC value based on the ADC interrupt? Or you are reading asynchronously the ADC FIFO at 50ms?

    how can i apply ADC_CLOCK_RATE_EIGHTH a second time?

    I didn't mean the second time. You still have not told me what is the sample rate you are observing when you use ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_EIGHTH, 15). 

    how can i check those registers?

    You can view them in the register window. 

    ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_RATE_FULL, 120); 

    is the full rate 240 Mhz or 480? anyway i am dividing by 120 so it should be around 2 or 4 Mhz and does that mean i am getting 125Ksps or 250Ksps, am i right?

    I guessed that if 16Mhz correspond to 1 Msps, 1Msps/8 = 125Ksps and so 16Mhz/8 = 2Mhz, correct?

    Due to an errata, the VCO output from the PLL will be 240Mhz. 

    You cannot divide by 64. You can try to divide by 60 and that will give you a 4Mhz ADC clock. At 4Mhz you should in theory get 256ksps. You can apply ADC_CLOCK_RATE_HALF and that should give you 125ksps.