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.

Question about ADC powered from main oscillator

Hi!

I want to use the adc to measure a channel single endedly. I tried it in my project, but the adc sequence interrupt never triggered, probably because the conversion did not start correctly.

To find the reason for that, I tried out the adc.c example from the stellarisware. Without modification it worked, but as soon as I changed the system clock settings from:   

//    SysCtlClockSet(SYSCTL_SYSDIV_10 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |
//                   SYSCTL_XTAL_16MHZ);

to

SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
                   SYSCTL_XTAL_16MHZ);

the conversion did not trigger and the program was stuck at the while(!ADCIntStatus(ADC0_BASE, 3, false)) .

I am using the evaluation board with the lm4f232H5QD, which has a 16MHz oscillator.

Is there anything I have disregarded?

Thanks for your help!

 Jan

  • Believe that the PLL must be enabled to insure that the ADC functions properly.  16MHz is the minimum recommended frequency required by the ADC - so you're OK as you've listed. 

    Avoid use of fractional dividers w/in your SysCtlClockSet() - or search this forum for my past finding/advice in this regard. 

  • Hi Jan,

    Please see item 10.4 A specific sequence is required when the MOSC is used to clock the ADC module in the Stellaris LM4F232H5QD Rev A1/A3 Errata (Rev. C).  You have to first power up the PLL, enable the clock to the ADC module, then disable the PLL and switch to the MOSC in order to get it to work.

    Regards,

    Sue

  • Bonjour Sue - (master puts interloper in proper place - again).

    Is disabling the PLL on an M4F almost the same as our Danica filling up with "Regular?"

  • Hi Sue and cb1,

    thanks for the advice. I have to admit, I did not regard the errata in this case.

    However in the errata is a suggested sequence (I changed the sysdiv_5 to sysdiv_4, because of Point 2.3 of the errata) :

     SysCtlClockSet(
       SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ
         | SYSCTL_OSC_MAIN);

     SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);

     SysCtlClockSet(
       SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_XTAL_16MHZ
         | SYSCTL_OSC_MAIN);

    I now employed this sequence.

    Yet this still only works, if I comment out the second sysCtlClockSet leaving the pll active.

     

    As additional information about the problem: I am working on a ccs5.2 IDE. I determine the working of the adc so far, by putting a breakpoint before the first processortrigger and after the following while (!ADCIntStatus(ADC0_BASE, 3, false)) loop, also monitoring the result in a variable. With pll, no problem. Without pll it will not pass the while loop.

  • Had past, similar issue - but did not involve bypass of PLL.  Perhaps of value - MCU was new 4X231 - IAR IDE.  Also became, "becalmed" w/in same while loop as you...

    Here's illustrating/test code - and several observations/suggestions:

            ROM_ADCProcessorTrigger(ADC0_BASE, 1);
            ulADCInt_count = 0;    //  zero so may be freshly updated & recorded
            
            while(!ROM_ADCIntStatus(ADC0_BASE, 1, false))
            {
                  ulADCInt_count ++;    //  monitors/confirms both "entry to & escape" from this loop
            }
           
            ROM_ADCIntClear(ADC0_BASE, 1);       
            ROM_ADCSequenceDataGet(ADC0_BASE, 1, g_ulADCData);

    Now - IAR reports that "ROM_ADCProcessorTrigger()" sets appropriate ADC Sequence bit w/in ADCRIS & ADCISC.  (possibly additional - those 2 for sure)   Checked/determined such by breaking right @ "ROM_ADCProc..." and then just post that instruction.  What I found interesting (and cannot yet explain) is that a successful entry into - and then proper escape from - the while loop did nothing to those bits earlier "set" w/in ADCRIS & ADCISC.  (they remained set - according to IAR - confounding my understanding of just how this loop was "escaped!")

    The following instruction: "ROM_ADCIntClear()" cleared both bits.   As I recall (will confirm in follow-up post later) without this ROM_ADCIntClear() - subsequent entry into ROM_ADCProcessorTrigger() will "hang" (just as you describe) w/in the stated "while" test.

    You may wish to test/verify - may be secondary issue but appears to deserve further investigation...

  • I just checked those bits in my routine.

    a) with PLL active: The ADCISC Bits never got set, but the ADCRIS  on Sequence 3 got enabled and then cleared after exiting the loop.

    b) with PLL deactivated (as specified in errata): Both Bits never get set. The loop is entered and never exited.

    I have not yet dug deeper into the ADCProcessorTrigger and ADCIntStatus functions. But I assume the problem might still a problem with the clocking of the adc.

    Regarding this case, the PLL PWRDN Bits in the SYSCT RCC and afterwards RCC2 Register got set correctly so I assume that according to the datasheet clocking diagram the adc should then be powered by the oscillator.

     Btw. the SYSCTL PLL Bypass Bit is set and the ADCCC Register is also correctly set on SYSPLL.

    Since I'm rather new to the ARM Devices I might be a little out of my league with this problem. I will try to stay with the pll enabled for the near time, but it would be nice to determine the root case of this problem. I wonder if the ADC was already used successfully with only the MOSC by someone else?

  • Thanks for your efforts - instructive & appreciated.  May I ask a follow-up - would you be so good as to "break" just after exit from the while loop - and check & report the status of ADCRIS at that point.  (paid/full ver. 6.4 IAR reports this bit "unchanged" (still set) upon exit from this while - which torments me!   The "false" parameter w/in ADCIntStatus() should cause looped testing against this exact bit - and as IAR reports it unchanged at exit - I cannot grasp how/why the while loop releases.)

    In my case, "ADCIntClear()" execution appears to be the only mechanism which clears this ADCRIS Sequence bit.  (I broke both @ this instruction - and then just after it - to confirm this observation.)  Would appreciate your/others repeat test/exam of my earlier listed ADC test snip - and feedback.

    Believe that you will gain high level response if you "justify" your motivation to bypass the PLL.  (earlier teased that slow-down of M4F seems unusual.)  You do gain power savings - however "throttled-down" M4F is not "usual/first suspect" when seeking power savings!   (can you say, "MPS-430?")  Many posts this forum - compelling issue - appealing to many - likely is best means to drive thoughtful response...

     

  • Hi cb1,

    i checked the ADCRIS Bit state, it was just as above. Almost immediately after The ADCProcessorTrigger was executed, the ADCRIS Bit gets set, therefore the while loop is not even executed once since the ADCIntStatus returns 1, which is negated by the "!" in the while statement. Then later the ADCIntClear removes the RIS Bit.

    Was this what you had in mind?

     

    About the bypassing of the PLL: My goal was to just use the external oscillator for every aspect and not use the PLL, because an accurate 16MHz is the Frequency I would like to use and since the Oscillator is giving that anyway it seemed like a waste to also use the PLL. I also wonder if it makes any differences in EMC whether the PLL is used or not, so for starters it's just basic MOSC. 

    At this stage I am only using the APIs for programming. The PLL Bypassing itself is done by the stellarisware routines I am using. I just doublechecked that it conforms with the datasheet to find the reason why my adc is not working without the PLL even though I use the way documented in the errata. However I found no further clues in the registers regarding that.

     

  • @Jan - thank you - you're prompt/detailed - appreciated... 

    Now to ADCRIS issue probe - to test successful entry/exit into the while loop I added an incrementing variable.  At times this variable failed to increment - yet the ADC conversions were performed - and w/in expected accuracy.  With the code snip I've provided (posts above) the while loop is most always entered - @ 50MHz SysClock the variable usually hits 30.  (note that I first clear it - and separately record/data-log for deeper review)   Jan - have you included this variable during your recent test?  If so - you must "clear" it as I've shown - as often the code will enter - and increment this variable "just once!"   (thus without the earlier "var clear" you could be led to believe that the variable is consistently being incremented - and more importantly - that the while loop has been repeated entered - when in fact it was entered only once!)  Please examine & report.

    You've explained your goal well - suggest that you confirm that MOSC provides the freq. accuracy required.  (recall some errata and/or limitation - may have been corrected)

  • Explanation of how I measured it:

    I used the code below which is quite similar to yours. The Clock Divider was 4, using the PLL. The variable was never incremented in this case, so the loop was not entered. I used different combinations of breakpoints to verify that. First at u_count_bsp=0, there the variable was already at 0. Then at ADCSequenceDataGet , there it was still 0, then at  u_count_bsp=0 I could see that a value was written in the ADC Value and at the next step the variable was set to 1. The main part of the program itself is encased in a while(1) loop.

    This was done with optimization disabled.

      ADCProcessorTrigger(ADC0_BASE, 3);
      u_count_bsp=0;
      //
      // Wait for conversion to be completed.
      //

      while (!ADCIntStatus(ADC0_BASE, 3, false))
      {
       u_count_bsp++;
      }
    //  u_count_bsp++;
      //
      // Clear the ADC interrupt flag.
      //
      ADCIntClear(ADC0_BASE, 3);
      //
      // Read ADC Value.
      //
      ADCSequenceDataGet(ADC0_BASE, 3, ulADC0_Value);
      u_count_bsp=1;

     

    Ok, while I was writing this, I did another run without breakpoints and this time it entered the loop and incremented the variable 11 times. I guess wiht breakpoints the adc did the sampling in the background so it was already finished before the while loop was executed.

    About the MOSC Frequency: I am quite sure the main oscillator is working correctly, since I let a pin toggle using a timer without the PLL and the result was the frequency I expected.

  • Appears that even though we both use new M4F (you 232, me 231) our results/observations - very similar. 

    In your specific case - perhaps it will be helpful to (temporarily) switch from ADCProcessorTrigger() to a Timer or PWM Enabled (or other) ADC Trigger.  (can't recall if PWM requires the PLL - certain that it does for HF operation of PWM)  Wonder if such switch "escapes" dreaded while, "hang?"

    Eureka moment (perhaps) - while loop is there so that ADC is not read, "prematurely."  Could not you eliminate the while loop with the insertion of SysCtlDelay() (or similar) delay loop (as replacement for while)  - set way high initially - 1Sec even.  Might this work for your ap?

    Believe we've, "beaten this to death" - need factory "know how/why" to dig deeper.  Good luck...

  • Thanks for your help.

    Though a different trigger is not really an option, so I will use the PLL with a frequency of 20 MHz and temporarily adapt the rest of the program to that.

    Since this ADC clocking seems to be an issue even after the errata, I am still hoping for information from TI on that. I will ask an FAE about that.

    If I get any more information regarding this, I will post it here.

  • Hi Jan,

    I've done some further research on this issue and I have determined that if you disable the PLL, the only option that works for clocking the ADC is using MOSC for the system clock and the PIOSC for the ADC clock.  You must first power up the PLL and configure the PIOSC as the ADC clock before you power it down and switch to the MOSC for the system clock.  I'm sure you have resolved your situation by now, but I just wanted to follow up on this thread with the additional information.

    Regards,

    Sue

  • Hi Sue,

    thanks for the reply. Nice to know that even old problem will not be forgotten. I will try this option in the next days to verify it.

    Best regards,

    Jan

  • I have spent hours upon days trying to figure out how to configure peripherals using TivaWare. I am particularly having issues getting my ADC and UART to work. I am pretty sure it's a clocking problem because I am doing everything exactly how the tiva examples show as well as many online examples. I am short on time and could use some help. I am using the TM4CXNCZAD. In particular, can somebody show me how to do what Jan is explaining above when she says, "You must first power up the PLL and configure the PIOSC as the ADC clock before you power it down and switch to the MOSC for the system clock." really need to see code snippets of how to do this. Thank you!

  • Hi Marshall,

    First, it is best to start a new thread, rather than posting on an old thread.  A new question attached to a resolved post is likely to be overlooked.

    Second, you did not include the full part number, but I assume you are using the TM4C129XNCZAD device.  

    Third, could you please specify the clock configuration you are trying to achieve?  Do you have an MOSC attached? What is its frequency? Do you want the ADC and UART to run off the system clock or from the PIOSC?  If you can clarify what you are trying to do, I'll help you with the code.

    Regards,

    Sue

  • Hi,

    I just encountered the same problem of running the ADC from the main oscillator (MOSC) on a TM4C1294K device.

    After days of fighting with the device, I eventually came across this post and finally got the ADC to work by configuring its clock before shutting off the PLL.

    The sequence is:

    1. set the system clock to run from the PLL

    2. enable the ADC

    3. Set the ADC clock to run from MOSC

    3. set the system clock to run from MOSC (turn the PLL off)

    the code looks like that:

    ui32SysClock = SysCtlClockFreqSet(SYSCTL_OSC_INT | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_320, 25000000);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);

    ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_MOSC | ADC_CLOCK_RATE_FULL, 0);

    ui32SysClock = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_OSC), 25000000);

    I didn't see any explanation about that, not in the data-sheet nor in the erreta of that device.

    Timor