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.

Sloving the problem with the ADC channel readings in CC5

Other Parts Discussed in Thread: CC430F5137

Hello,

Can someone help me out with the problem facing with this code

Original code and description by old_cow_yellow

Description:The buffer size of 1000. Thus when you stop it anytime after 2 seconds of running, there are 1000 most resent results in the array results[0...999] for you to inspect. Do not use debug single-step or break-point.

 I do not have CC430F5137. It is suppose to read the internal temperature sensor every 2 msec. If you heat up or cool down the chip a few degrees, and repeat the test, you should be able to see the difference between the two sets of data. You should be able to see the slight variation within each set too or even the difference between the beginning and the ending the 2 seconds.

#include <msp430.h>
#define Smclk 1048576u /* default frequency */
#define Size 1000 /* size of result buffer */

__no_init volatile unsigned results[Size];
volatile int oldest = 0;
volatile int filled = 0;

void main( void )
{
  WDTCTL = WDTPW + WDTHOLD;

// Initialize ADC12_A to sample internal-temperature-sensor
  REFCTL0 = REFMSTR + REFON;
  ADC12CTL0 = ADC12SHT0_4 + ADC12REFON + ADC12ON;
  ADC12CTL1 = ADC12SHS_1 + ADC12SHP + ADC12CONSEQ_2;
  ADC12CTL2 = ADC12PDIV + ADC12RES_2;
  ADC12MCTL0 = ADC12SREF_1 + ADC12INCH_10;
  P2SEL = BIT2;
  ADC12IE = ADC12IE0;
  ADC12CTL0 |= ADC12ENC;

// Set up TA0CC1 to generate a 500 Hz square wave to start ADC12 conversion
  TA0CCR0 = Smclk/(500) - 1;
  TA0CCR1 = TA0CCR0 - 20;
  TA0CCTL1 = OUTMOD_3;
  TA0CTL = TASSEL_2 + MC_1;

  while (1)
  {
    __bis_SR_register(CPUOFF + GIE);

// Do data processing here
// The oldest result is in results[oldest]
//   ...   ...  ...  ...
//   ...   ...  ...  ...
//   ...   ...  ...  ...
// This must be accomplished well within 2 msec.
// You may need to increase the core voltage and speed up MCLK

  }
}

#pragma vector=ADC12_VECTOR
__interrupt void ADC12ISR(void)
{
  ADC12IV;
  results[oldest++] = ADC12MEM0;
  if (oldest >= Size)
  {
    oldest = 0;
    filled = 1;
  }
  if (filled)
  {
    __bic_SR_register_on_exit(CPUOFF);
  }
}

old_cow_yellow :I don't have CCS so I don't know what is the problem.

Can someone inspect this in sloving the below

when I tried to look into the ADC register section in the debug window by running this programme by changing ADC12INCH_2;  P2SEL = BIT2; it was showing "error:unable to read".

Here in the programme it says "Do data processing here" means that displaying the last sampled ADC value i.e, results[oldest] .

Actual programme should read ADC values continuoulsy with a sample rate of 500Hz as mentioned in the programme with a timer.

Thanks.

 

 


 

 

 

  • Doubt it will answer your question, if any, but just curious - about meaning of ADC12IV in your ADC ISR code?


  • HI Ilmars,

     Frankly speaking I also don't know the meaning.I was just curious about its working but its not working.

    Can someone explains what does this mean.

     

  • stefan 12 said:
    Can someone explains what does this mean.

    If you don't know then why you put it into your source code? Where it came from?

  • Remove ADC12IV, add some NOP's and follow instruction:

    // The oldest result is in results[oldest]
    //   ...   ...  ...  ...
    
    _NOP();
    _NOP(); // put breakpoint here and see results[] when fired
    // This must be accomplished well within 2 msec.
  • Ilmars,

    The ADC12IV was there in the code made by  .

    I changed as you instructed but teh breakpoint is never executing and window shows running as shown

    I don't know what is the problem.

     

     

  • stefan 12 said:
    The ADC12IV was there in the code made by  .

    In Cow's code it is comment. Not always comments contain actual code you can compile.

    stefan 12 said:
    I don't know what is the problem.

    So find it. Using debug.

    Place breakpoint in the ADC ISR, see if it is running. If not - then think what's wrong with it. Maybe something wrong with ADC setup or conversion start (signalling).

    It is not productive to sit and wait while others will tell you what to do. So instead of "I compiled it, does not work, please help" you shall say: I tried this and that, got following results and so on..

  • llmas,

    In fairness, stefan did try many times, and many ways (ways that I do not understand). I do not know how to use CCS and do not know what that debugger can and cannot do. My suggestion was, as a first step, do the following:

    1. Start to run the code as is. Do not use single-step, break-point, or anything else that might impede free running.

    2. After the code runs freely for a few seconds, stop the run.

    3. Examine the resulting global variables oldest, filled, and results[0...999]

    I was told that the CCS debugger cannot do that (specifically, item 3 above) 

    -- OCY

    BTW. I think the line ADC12IV; you pointed out is useless but harmless. Only one of the possible ADC12 interrupts is enabled. Under this circumstance, the reading is 6 which is ignored. The corresponding IFG is cleared, which the next statement will clear anyway. The only effect is that we wasted a few MCLKs.

  • Thanks a lot old_cow_yellow for supporting me for the work I did.

    llmas I really worked out in different  aspects to figure out the problem and was also wondering like "can I really point out something that makes it code workable?" as it was coded by the geek coder old_cow_yellow.

    Hope this will make some difference in your(llmas) opinion about me.

    I hope you will help me out in solving the problem.

    stefan.

  • I just want to make this clear

    The only problem with the code is its not working when trying to copy the ADC12MEM0 results into an array as the required is to collect 500 samples in 1 sec like in  this piece of code

    __interrupt void ADC12ISR(void)
    {
      results[oldest++] = ADC12MEM0;
      if (oldest >= Size)
      {
       oldest = 0;
        filled = 1;
      }
      if (filled)
      {
        __bic_SR_register_on_exit(CPUOFF);
      }
    }
    

    It's working well when only single ADC convesion value in ADCMEM0 is taken and displayed on hypertermianl in 0.937ms i.e, <2ms  

    while (1)
      {
    	  conv(result);//displaying on the UART in <2ms
    	  ADC12CTL0 |= ADC12SC;
        __bis_SR_register(CPUOFF + GIE);
      }
    }

    The UART baudrate used was 9600 which requires 0.9375ms per character.So, I am extarcting the last value of the integer

    and converting into ASCII which will printed in 0.937ms.

    The ADCconversion value displayed on the terminal in the programme is verified by checking the last digit in the actual ADC value

    as shown in the below image where first set of values represeting the ADC values by repeated conversions of singel channel and second set of values is the obtained ADC conversion value displayed in the main while(1).

    thanks.

  • stefan 12 said:
    The only problem with the code is its not working when trying to copy the ADC12MEM0 results into an array as the required is to collect 500 samples in 1 sec like in  this piece of code

    And again you are not telling how exactly it is not working, what you tried to fix it and what results you get for each action of yours. This 500 sample ADC ISR is not called at all or what? You shall give more input instead of "it is not working, here's code".

  • Yes, the 500 samples ADCISR is not called at all and I verified it by trying to display the collected sample results[oldest] main while() actual it should display last digit like if ADC reading is 379 it should display 9 which will done in 0.9375ms(<2ms) as explained above.

    This is what I analysed.

  • stefan 12 said:
    ADCISR is not called at all and I verified it by trying to display the collected sample

    ISR you verify not by displaying data by putting breakpoint into it. Did you do that?

  • I re-read my code and still cannot find anything wrong. Of course this does not mean it is right ;)

    I also reviewed the "problems" you had. I do not have the CC430F5137 or anything remotely similar to it. And I do not know anything about the CCS debugger. But I suspect those "problems" are cussed by the expectation or the way you used the CCS debugger. For example, the screen-shot in the 6th posting in this thread showed "Error: unable to read" those items you asked it to read while "Running".

  • ThanksATon old_cow_yellow,

    Yes, there is no error and it is working fine.Iam really sorry as I was not able to understand that ADC cannot read while running as you said" "Error: unable to read" those items you asked it to read while "Running"".

    Only thing is it's not working with the 500 samples ADCISR as explained in the 10 and 11 posts of this thread I guess.Is there something wrong with my working procedure.

     .

  • Hello,

    Can anyone help me out in sloving the issue of saving the ADC12MEM0 values into an array of size 500.

    Thanks.

  • stefan 12 said:

    Hello,

    Can anyone help me out in sloving the issue of saving the ADC12MEM0 values into an array of size 500.

    Thanks.

    The required change is shown below in red. It was 1000 before the change.

    #include <msp430.h>
    #define Smclk 1048576u /* default frequency */
    #define Size 500 /* size of result buffer */
    __no_init volatile unsigned results[Size];
    volatile int oldest = 0;
    volatile int filled = 0;
    void main( void )
    {
      WDTCTL = WDTPW + WDTHOLD;
    // Initialize ADC12_A to sample internal-temperature-sensor
      REFCTL0 = REFMSTR + REFON;
      ADC12CTL0 = ADC12SHT0_4 + ADC12REFON + ADC12ON;
      ADC12CTL1 = ADC12SHS_1 + ADC12SHP + ADC12CONSEQ_2;
      ADC12CTL2 = ADC12PDIV + ADC12RES_2;
      ADC12MCTL0 = ADC12SREF_1 + ADC12INCH_10;
      P2SEL = BIT2;
      ADC12IE = ADC12IE0;
      ADC12CTL0 |= ADC12ENC;
    // Set up TA0CC1 to generate a 500 Hz square wave to start ADC12 conversion
      TA0CCR0 = Smclk/(500) - 1;
      TA0CCR1 = TA0CCR0 - 20;
      TA0CCTL1 = OUTMOD_3;
      TA0CTL = TASSEL_2 + MC_1;
      while (1)
      {
        __bis_SR_register(CPUOFF + GIE);
    // Do data processing here
    // The oldest result is in results[oldest]
    //   ...   ...  ...  ...
    //   ...   ...  ...  ...
    //   ...   ...  ...  ...
    // This must be accomplished well within 2 msec.
    // You may need to increase the core voltage and speed up MCLK
      }
    }
    #pragma vector=ADC12_VECTOR
    __interrupt void ADC12ISR(void)
    {
      ADC12IV;
      results[oldest++] = ADC12MEM0;
      if (oldest >= Size)
      {
        oldest = 0;
        filled = 1;
      }
      if (filled)
      {
        __bic_SR_register_on_exit(CPUOFF);
      }
    }

  • Hello OCY,

    Here the array size is being limiting to 476 and it is not working for >476.This I verified by sending ADC12MEM0 value to the hyperterminal in <2ms and is working fine for the array size upto 467 nad not for >476.

    And in CCS  using __no_init infront of volatile unsigned results[Size] gives the syntax error and shows a error like volatile unsigned results[Size]is undefined so just used volatile unsigned results[Size].

    Thanks,

  • I do not use CCS. The two problems you found are probably related. The code generated might have tried to initialize the array with the WDT clocked by the SMCLK in the "watch-dog-mode". When the size of the array is small, this works. When the size is big, the WDT expires before the initialization finishes all the elements of the array.

    This is probably an old problem and there probably are ways to work around it.

    BTW, the startup code should not have taken anywhere near 32000 MCLKs even if there are 500 words to be cleared and the SP needs to be loaded. The startup code is probably very inefficient too.  

  • OCY is there any solution to overcome this.As I need to get 500 samples for my next processing.

    thanks.

  • old_cow_yellow said:
    The startup code is probably very inefficient too.  

    Depends on the viewing angle.

    IIRC, the latest version uses compressed storage for init values. Decompression is slow then, but probably saves a lot of flash space. Unfortunately, it makes it more likely that the watchdog barks before main is reached. And an array, even if only one element is initialized, is put into the initialized data section and therefore initialized by decompressing  zero values.

    But to quote Stefan12: "I do not have CC430F5137." So what MSP do you have? And what compiler do you use?

  • stefan 12 said:

    OCY is there any solution to overcome this.As I need to get 500 samples for my next processing.

    thanks.

    This is probably an old problem and there probably are ways to work around it. But I do not use CCS and I do not know. However, I am certain that others have discussed this before.

  • Jens-Michael Gross said:

    ...

    But to quote Stefan12: "I do not have CC430F5137." So what MSP do you have? And what compiler do you use?

    JMG,

    Stefan12 was quoting me (i.e., OCY does not have CC430F5137). He has it and is using it.

    --OCY

  • old_cow_yellow said:
    Stefan12 was quoting me (i.e., OCY does not have CC430F5137). He has it and is using it.

    Okay, I wasn't aware that the text was a quote.
    Well, the 5137 has 4k of SRAM, so 500 or even 1000 ints won't fill it (or else the linekr would have complained anyway) but the remaining space is also large enough to not suffer from a stack overflow (only a few bytes stack are required for this program).
    The counter and flag variables are volatile, no interrupt nesting, no pointer usage, WDT is off, no unhandled interrupts enabled, all seems well.

    Reading ADC12IV is not required. The only active ADC12IE bit is IE0, and while reading ADC12IV would clear it, this also happens when ADC12MEM0 is read  in the next line.

    The only thing that's questionable is the 'default frequency'. The FLL initializes to 31*REFO. So after some time, it will stabilize around 1.016MHz (+-1.5%)

  • Hello JMG and OCY,

    Anyways I'm not using ADC12IV and the code works fine collecting upto 476 is as follows

     
    main()
    {
    #define Size 476 /* size of result buffer */
    volatile unsigned results[Size];
    volatile int oldest = 0;
    volatile int filled = 0;
    while (1)
      {
    	  Uart_send(results[oldest]);//displaying hyperterminal
    	  ADC12CTL0 |= ADC12SC;//start ADC conversion(after 2ms of timer)
        __bis_SR_register(CPUOFF + GIE);//CPU OFF mode
      }
    }
    
    #pragma vector=ADC12_VECTOR
    __interrupt void ADC12ISR(void)
    {
      //ADC12IV;
    	results[oldest++] = ADC12MEM0;
      if (oldest ==475)
      {
    	  oldest= 0;
      }
        __bic_SR_register_on_exit(CPUOFF);
    }

    How to get the 500 samples of ADC12MEM0 for which a averaging window(smoothing) will be perfomed later.

    Thanks.

     

  • stefan 12 said:
    main()
    {
    #define Size 476 /* size of result buffer */
    volatile unsigned results[Size];

    this will define a local array in main. It pushes the stack by 952 bytes - and is not reachable by the ISR at all.  Same for 'oldest'.
    Not to mention that the code doesn't initialize the ADC. Also, I think it makes no sense sending a result before any samples were collected. And sends the array element that will be filled next (but hasn't been filled yet).

    I really doubt that 'the code works fine'. Not the code you posted.

  • Hi JMG,I made a mistake while copying "#define Size 476 /* size of result buffer */ " and now I also changed the way samples are sent and it looks like 

    #define Size 476 /* size of result buffer */
    volatile unsigned results[Size];
    volatile int oldest = 0;
    volatile int filled = 0;
      main
    {
    while (1)
      {
    	  UART_send(results[oldest]);
    	  ADC12CTL0 |= ADC12SC;
        __bis_SR_register(CPUOFF + GIE);
      }
    }
    }
    
    #pragma vector=ADC12_VECTOR
    __interrupt void ADC12ISR(void)
    {
    	  if (oldest == 475)
    		   {
    		  oldest= 0;
    		   }
    		  else
    		  {
    	          oldest=oldest+1;
    		  }
    	  results[oldest]=ADC12MEM0;
        __bic_SR_register_on_exit(CPUOFF);
    }
    And  samples are being stored upto the array size of 467 only.

     I didn't get this"Not to mention that the code doesn't initialize the ADC".

    Thanks.

     

  • stefan 12 said:
    And samples are being stored upto the array size of 467 only.

    Are you getting meaningful data on output? Maybe your ADC does not fill ANY data and you are seeing something else?

    Try:
    fill all the result[] array with "filler" data like 1234 value,
    output whole array to PC to check that you see 476 entries of filler value 1234,
    then init ADC and run data collection,
    then output whole array to PC to check which part of buffer is filled with ADC data and which part still have filler.

  • I am able to see the actual signal what I am seeing on CRO.

    I collected the continuos samples using the Matlab programme and plotted the uisng 500 samples i.e., for every 1 sec which is as shown here http://imageshack.us/photo/my-images/826/2yqg.png/  (and is similar to the one on CRO).

    But the only problem is I am unable to save the more than 476 ADC samples in a array.

     

  • Kudos to OCY

    Your suggestion solves the entire problem by suing these lines

    	 int _system_pre_init(void)
    	{
    	   WDTCTL = WDTPW | WDTHOLD;
    	   return(1);
    	}
    

    And by disabling the WTD

    void main( void )
    {
      //WDTCTL = WDTPW + WDTHOLD;//Watchdog
    }

    Thanks for giving your time in solving this.


     

     

  • Hello OCY,

    And I am left with 1 more thing and need your suggestion to add another timer of 10 sec in the programme and the working should be something like this

    The Timer of 2ms is collecting 1 sample making a total of 500 samples in 1 sec,once the 500 samples are filled(collected) the 500 samples are checked in a loop to see how many samples have(crossed)  a value > threshold value.After 10 secs interval the counted values of samples >threshold has to be sent to the hyperterminal.

    Thanks.

     

     

     

  • I do not think you need to use another Timer. You are currently using TimerA0 to start DAC12 conversions. If you set the CCIE of TA0CTL0 without changing any other settings, you will get an interrupt every 5 2 msec. In the corresponding ISR, you could count that interrupt in units of 5 2 msec. That is, 200 500 counts = 1 second, 2000 5000 counts = 10 seconds, etc.

  • To keep a number (Size) of the most resent ADC readings, I was using a circular buffer results[Size] and an index oldest. It appears to me that this method is too opaque and you were only able to use the oldest data in results[oldest].

    There are other ways to do this. For example, TI’s Application Report SLAA357–March 2007 "Efficient MSP430 Code Synthesis for an FIR Filter" uses variable such as:

        int input_delay0;
        int input_delay1;
        int input_delay2;
        int input_delay3;
        int input_delay4;
        int input_delay5;
        int input_delay6;
        int input_delay7;
        int input_delay8;
        int input_delay9;
        int input_delay10;
        int input_delay11;
        int input_delay12;
        int input_delay13;
        int input_delay14;
        int input_delay15;
        int input_delay16;
        int input_delay17;
        int input_delay18;
        int input_delay19;
        int input_delay20;

    Whenever, new ADC readings are available, the above variables are updated as follows:

        input_delay20 = input_delay19;
        input_delay19 = input_delay18;
        input_delay18 = input_delay17;
        input_delay17 = input_delay16;
        input_delay16 = input_delay15;
        input_delay15 = input_delay14;
        input_delay14 = input_delay13;
        input_delay13 = input_delay12;
        input_delay12 = input_delay11;
        input_delay11 = input_delay10;
        input_delay10 = input_delay9;
        input_delay9  = input_delay8;
        input_delay8  = input_delay7;
        input_delay7  = input_delay6;
        input_delay6  = input_delay5;
        input_delay5  = input_delay4;
        input_delay4  = input_delay3;
        input_delay3  = input_delay2;
        input_delay2  = input_delay1;
        input_delay1  = input_delay0;
        input_delay0  = new_ADC_reading;

  • Hi OCY,

    I guess using the TACCTL0 |= CCIE;  will make an  interrupt for CCR0 but didn't got of how the interrupt will be genearted for every 5msec as the timer currently using is of 2ms.

    Thanks.

  • You were right.Sorry I made a mistake.

    You will get that interrupt every 2 msec, not 5 msec.

    Thus count 500 => 1 second. Count 5000 => 10 sectonds

  • Hello OCY,

    I mean how to manage the two counts to  execute a thing after a particular count like after 5000 counts it should send the count value through UART_send(); and after 2msec counting ADC start.

    Also for the efficient working where the condition should be placed  in ADCISR  or in the 2msec ISR i.e., if filled ADC values =500 it should check all the values in loop for a vaue > threshold and incrementing the count if anything found in these samples which will be sent after 10sec.

    Thanks.

  • I already admitted and told you that I made a mistake. And I also edited and corrected the original posting that had the mistake. Please go back and re-read those postings.

  • Yes OCY,

    I just corrected the above post which I was intended to ask about.

    Thanks.

  • stefan 12 said:
    Your suggestion solves the entire problem by suing these lines
    	 int _system_pre_init(void)
    	{
    	   WDTCTL = WDTPW | WDTHOLD;
    	   return(1);
    	}


    I cannot believe that filling 476 words with zeroes will take so much timer that the WDT expires.
    Either the boot code is extremely long or something else eats up time. It's more than 50 clock cycles per word.
  • My sentiment too!

    But …

    Jens-Michael Gross said:

    The startup code is probably very inefficient too.  

    Depends on the viewing angle.

    IIRC, the latest version uses compressed storage for init values. Decompression is slow then, but probably saves a lot of flash space. Unfortunately, it makes it more likely that the watchdog barks before main is reached. And an array, even if only one element is initialized, is put into the initialized data section and therefore initialized by decompressing  zero values. ...

    [/quote]

  • old_cow_yellow said:
    But …

    Right. Yet I cannot believe that the decompression algorithm will take 50 or more clock cycles per word. It will give a horrible startup time until main is reached.

    not to mention that disabling the watchdog counteracts the purpose of a watchdog. (I once wrote my own startup code for MSPGCC, to keep the watchdog active but triggered during startup)


  • Hello,

    Can I know how to add a counter of 1 sec like counting upto a value of 500 each of 2ms as the current one is of 2ms.I want to send all the 500 samples(each collected in 2ms) obtained after a 1 sec.I am now sending the ADC sample in <2ms  to the hypertermianl using UART baudrate of 115200.

    How to parallely process the sending of 500 samples to the UART after 1 sec as well the ADC conversion in every 2msec.

    Thanks.

**Attention** This is a public forum