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.

Weird variable loop resetting when using the 10 bit ADC and a PWM output

Other Parts Discussed in Thread: MSP430G2553

I've been working on some code that will eventually put out an analog drive voltage, (using PWM and a low pass filter), and read in a few analog inputs. Right now it just produces a drive voltage, measures it using the ADC, and then outputs back the mirror image to make sure the ADC read everything. Whenever I tested my code with all the ADC references taken out, it worked fine. In fact, it still works perfectly fine if I comment out this one line: 

voltage[i] = ADC10MEM; 

Does anyone know why this line is preventing the for loop its in from completing and causing it to reset? (Note: I'm monitoring the output using a digital oscilloscope and the microcontroller is a MSP430G2553). The voltage array is an array of ints. For completeness here is the for loop:

for (i=499, k=0;i>=0;i--){
     CCR1=i<<1;
     //delay to allow the filter and capacitance in solar panel to stabilize
     for (j=1000;j>0;j--);
     ADC10CTL0 |= ADC10SC; //Sampling and conversion start

     voltage[i] = ADC10MEM;

}

And here is the whole code:

#include <msp430g2553.h>

/*
* main.c
*/

void ConfigureAdc(void); //prototype for function that configures ADC, taken from
                                             //enrico::garante, http://www.egarante.net/2011/05/msp430-launchpad-tutorial-part-3-adc.html

int main(void)
{
          WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer

//Arrays to hold data points
int voltage[500];
//float current[500];

//Voltage divider for measuring voltage of panel, shunt resistor for measuring current
float voltageDivider=11.1;
float shuntResistor=0.1;

int i, j, k=-1; //counting variables

//Sum of readings to be averaged
float voltageSum, currentSum;


/******************DRIVE VOLTAGE SECTION******************/
P1DIR |= BIT6; //P1.6 to output
P1SEL |= BIT6; //P1.6 to timer output bit TA0.1

CCR0 = 1000-1; //PWM Period
CCTL1 = OUTMOD_7; //CCR1 reset/set
CCR1 = 1000; //CCR1 PWM duty cycle
TACTL = TASSEL_2 + MC_1; //SMCLK, up mode

/*****************ADC SECTION****************************/
BCSCTL1 = CALBC1_1MHZ; //Set range
DCOCTL = CALDCO_1MHZ;
BCSCTL2 &= ~(DIVS_3); //SMCLK=DCO=1MHz
P1SEL |= BIT5; //ADC input pin P1.5

ConfigureAdc ();

ADC10CTL0 |= ENC; //ADC enable

/****************EXECUTION SECTION*******************/
for (i=499, k=0;i>=0;i--){
        CCR1=i<<1;
        //delay to allow the filter and capacitance in solar panel to stabilize
        for (j=1000;j>0;j--);
        ADC10CTL0 |= ADC10SC; //Sampling and conversion start
        voltage[i] = ADC10MEM;
}
CCR1 = 1000;

for (i=499, k=1; i>=0; i--){
       CCR1=voltage[i];
       for (j=1000;j>0;j--);
}
k++;

CCR1 = 1000;

while(1);


return 0;

}

void ConfigureAdc (void)
{

ADC10CTL1 = INCH_5 + ADC10DIV_3; //Channel 5, ADC10CLK/4
ADC10CTL0 = SREF_0 + ADC10SHT_3 + ADC10ON + ADC10IE; //Vcc and Vss as reference
ADC10AE0 |= BIT5; //P1.5 ADC option

}

  • > int voltage[500];

    The G2553 has only 512 bytes of SRAM -- absolutely no more than 256 "int"s, and in practice much fewer.

    If this array had been global, the linker would have noticed and fussed, but since it's in the stack (I suggest not doing that) the compiler proper was the only one who could (theoretically) figure it out, and it didn't.

    If you do want to put a large, or even large-ish array in the stack, you should check your stack size (different procedures for CCS and IAR) since the default sizes are usually pretty small.

  • I wonder why the compiler/linker let you declare 500 integers with MSP430G2552. It is not possible and causes problems.

    Which compiler/linker are you using? And what chip did you tell it?

  • This variable was in the stack, so detecting the overage would have required a stack analysis. This analysis is (in general) impossible, and (in practice) messy. It also requires being able to see the entire program, and the compiler only sees one module at a time. Linkers don't usually do it automatically.

    This case was obvious, but stack overage bugs are (in general) not so obvious.

    I recently ran across a stack analyzer buried somewhere in CCS, but haven't used it yet.

  • old_cow_yellow said:
    I wonder why the compiler/linker let you declare 500 integers with MSP430G2552.

    Why not? Thes were local vars. The compiler doesn't know how much ram (or flash) the target processor has. And the linker doesn't know that the compiler-generated code will throw 1000 bytes on the stack. (As well as it couldn't know that texecuting the code migh tlead to endless recusrions, making the stack overflow, or other things)

    When designing the program, one step should have been to count the amount of space required for funciton calls, ISRs, local variables, then add some safety margin and enter this as stack size in the project settings. However, there is the most likely still the default value of 70 or 80 bytes. And the linekr only ensures that these 80 bytes are available after placing all global variables.
    If a proper estimation of the required stack size had been set in the project settings, the linker would have cried loud.

**Attention** This is a public forum