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.

ADC10, Repeat Secuence Channels and DTC One block

Other Parts Discussed in Thread: MSP430G2553

Hi,


I am trying to read two channels, P1.0 and P1.3, in a msp430g2553. I have configured the ADC10 in repeat secuence channels mode. I want to read this two channels in a block of 40 samples ( 4 channels x 10 secuences) , next calculate the avg of each channel and show it in a LCD pannel, all of this repeatedly. The two signals to sample are sinusoidal signals.

1. The first problem is that the buffer area for the samples is not exclusive for this. When I debugg and show the memory 0x200 I see other variables and then its are overwritten. How it made for what the variables aren't in the buffer zone of the ADC? I have tried to assign them to another memory area, eg 0x1000, but nothing is saved and the device is reset.


2. If I want to increment the number of samples to 240 conversions, then the device is reset to the second o third block conversion. I noticed that in position memory 0x3b0 appears the label "_stack". What is this, I can not access those positions??

Error: program will not fit into available memory.  run placement with alignment fails for section ".stack" size 0x50 .  Available memory ranges:    lnk_msp430g2553.cmd

If my buffer is defined  with array of 100 positions, the error does not appear.


3. How I can make my variable is assigned to the position of 0x200 memory?


This is part of my code:

unsigned char capture=0;
unsigned char ADCDone=0;
unsigned int sumV,sumI,instP,sumP;              

long lastFilteredV,filteredV;                   
long lastFilteredI, filteredI;

volatile unsigned int buf_adc[50];

const unsigned char NSAMPLES = 48;


int main(void) {

    unsigned char start=0;

    WDTCTL = WDTPW | WDTHOLD;    // Stop watchdog timer
    
    //Setup Clocks
    DCOCTL = CALDCO_1MHZ; //Internal oscillators frequency
    BCSCTL1 = CALBC1_1MHZ;
    BCSCTL1 |= DIVA_1; // ACLK/8 - wake up about every 26 seconds (WHEN DIVA_3 - about 6 seconds for DIV 1)
    BCSCTL2 = DIVS_0; // SMCLK = DCOCLK/0 - SPI (USCI) uses SMCLK, prefer SMCLK < 10MHz (SPI speed limit for nRF24 = 10MHz)
    BCSCTL3 |= LFXT1S_2; // ACLK = VLO
    while (BCSCTL3 & LFXT1OF)
        ;  // Wait until the VLOCLK is up, running & stable

    start = 1;
    
    lcdi2c(0x27, 20, 4);      //Assign address LCD and type
    init();                   //Init i2c bus and lcd
    backlight();              //Switch on LCD


    ConfigureAdc();

    __bis_SR_register(GIE);            // interrupts enabled

    while(1) {
        if (start) {
            ADC10CTL0 &= ~ENC;
            while (ADC10CTL1 & BUSY); // Wait if ADC10 core is active
            ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start
            __bis_SR_register(CPUOFF + GIE); // LPM0 with interrupts enabled
            start = 0;
        }
        //Calculamos la suma
        if (ADCDone) {
            Calculo();    

            //Show vars in the LCD
        //...
            
        ADCDone = 0;
            capture = 1;
        }

        if (capture== 1) {
            ADC10SA = (unsigned int) &buf_adc;        //Dir Inicio
            ADC10DTC0 |= ADC10CT;
            //Modo LPM0
            __bis_SR_register(CPUOFF + GIE);           // LPM0, the ADC interrupt will wake the processor up.
            capture = 0;
        }

    }

    return 0;
}



void ConfigureAdc(void)
{
    /* Configure ADC Channel */
    ADC10CTL1 = INCH_3 + ADC10DIV_1 + ADC10SSEL_3 + CONSEQ_3; // Channel 43210, ADC10CLK, SMCLK, Repeat varios CH
    ADC10CTL0 = REFOUT + REFON + ADC10SHT_3 + MSC + ADC10ON + ADC10IE; //
    ADC10CTL0 &= ~REF2_5V; // 1.5V Reference
    ADC10AE0 |= BIT0 + BIT3; //P1.0 + P1.3 ADC option

    ADC10DTC0 &= ~ADC10TB;     //Mode ONE BLOCK TRANSFER
    ADC10DTC1 = 48;         //Values to save = 48 samples (12 samples x channel)
    ADC10SA = (unsigned int) &buf_adc;        //Dir Ini

    ADC10DTC0|=ADC10CT;    //
}

void Calculo(void)
{
    volatile unsigned int positiveV,positiveI;
    volatile unsigned int lastSampleV;   //sample_ holds the raw analog read value, lastSample_ holds the last sample
    volatile unsigned int lastSampleI;
    volatile float VRATIO, IRATIO;
    unsigned char i;

    lastSampleI = buf_adc[0];
    lastSampleV = buf_adc[3];

    lastFilteredV = filteredV;                    //Used for offset removal
    lastFilteredI = filteredI;                    //Used for offset removal

    //Sumatorio
    for (i=0; i < NSAMPLES; i++) {

        filteredV = 1 *(lastFilteredV+ (int)(buf_adc[(i*4) + 3]-lastSampleV));
        filteredI = 1 *(lastFilteredI+ (int)(buf_adc[i*4]-lastSampleI));

        if (filteredV < 0) {
            positiveV = ~filteredV +1;
            sumV += positiveV;
        }
        else
            sumV += filteredV;                      

        if (filteredI < 0) {
            positiveI = ~filteredI +1;
            sumI += positiveI;
        }
        else
            sumI += filteredI;                      

        lastSampleI = buf_adc[i*4];
        lastSampleV = buf_adc[(i*4) + 3];

    }

    //Calculo VIP
    //...

    //Reset accumulators
      sumV = 0;
      sumI = 0;
      sumP = 0;
}

// ADC10 interrupt service routine
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR (void)
{
    ADC10DTC0 &= ~ADC10CT;    //Stop sample & conversion
                            //If you want come back to begin the samples, ADC10CT =1
    ADCDone = 1;
    __bic_SR_register_on_exit(CPUOFF); // Return to active mode
}

Thanks.

  • The G2553 has a maximum of RAM memory of 512 bytes. From this RAM memory there is part reserved for ‘Stack’. To check what you are currently using you can read it in the “<configuration name>\project name>.map” file.

    Federico Montenegro said:
    I noticed that in position memory 0x3b0 appears the label "_stack". What is this

    Here you hits the ‘Stack’, ‘&_stack’ is the first (lowest) byte in the stack, writing from here will crash your program.

    Federico Montenegro said:
    Error: program will not fit into available memory.  run placement with alignment fails for section ".stack" size 0x50

    For your stack is reserved 0x50 (80) bytes, so you have left for your program 512-80=432 bytes but you go over it. It is possible to decrease the stack size, you could try 40 bytes but be careful if your stack flows the program will also crash.


  • Thanks for your reply!!!

    Then, all variables of my program have occuped 432 bytes of RAM. I guess increasing the buffer array in 40 bytes I will decrease the stack size??


    In the ADC10-DTC, is only possible to use the RAM area to record the samples? or you can use another memory area?


    Thanks.

  • Hi Federico,

    While working with ValueLine series (MSP430G), I've a practice sampling ADC channels and storing+adding into an array. I recommend you to follow this.

    The process is like this:

    1. Initialize a timer with an interrupt on desired period, eg: 250uS. Initialize an array, 'ADC_Avg' of size 'Num_Channels' with zero.

    2. On each interrupt, sample values of each ADC channels that you want to measure.

    3. Add the value of each channel to the respective array. "How many times to add?" -> choose "4", "8" etc, ie., nth power of 2. 

    4. After "n" number of timer interrupts, find the average by dividing with "n". Since it's power of 2, you can perform  "ADC_SUM >> n" operation

    To get the better results of conversion, I suggest you to read "slau144 - MSP430x2xx Family User's Guide". Under ADC10 Section, you can find "22.2.5.1 Sample Timing Considerations". I recommend you to read it to match the effective resistance for total sampling time required and all related information.

    Regards,

    Binoy Raphael.

  • Federico Montenegro said:
    I guess increasing the buffer array in 40 bytes I will decrease the stack size??

    You can try.

    Federico Montenegro said:
    In the ADC10-DTC, is only possible to use the RAM area to record the samples?


    Yes

    Federico Montenegro said:
    or you can use another memory area?

    No
     

  • Hi Binoy, first thanks for your reply.


    I want to sample AC signal (230V with trafo AC-AC to 1.5V ac). Then, the frecuency is 50Hz.

    It is best to sample at a given time as comets? or sample a block, calculate, and then sample another block?
     
    Regards, Federico.
  • Hi Federico,

    Now things are a little more clear.

    If you want to display the waveform of 50Hz signal, you may have to think about the time required for the conversion and average process.

    If you want to capture 40 samples, you will need to consider "40 * conversion time of one sample". The conversion has to be calculated from the connected total resistance (Go through "Sample Timing Considerations"). In one of my example, the conversion time required for 13.5uS (ADC frequency was 4MHz, I guess). But of course if you do in sequence mode, the total time required will be less then the product of "40*conv. time".

    I still recommend you to use an array and to average the number of times you want that.

    For averaging, you can directly divide it by 10 (It'll consume more storage space and CPU cycles).

    I implemented my code for two ADC channels and it was for an adjustable soldering station, and it consumes only 50 Bytes of RAM (Not the ADC part, the entire program needs only 50 bytes of RAM, inclusive of stack). If you're interested, I can give you the source code of ADC part. All you have to do is, just define your channels in that and run the program.

    I also recommend you not to attempt to store any values directly to the RAM since the stack size can overwrite your memory in case of more interrupts.

    Now the plotting part:

    Since 50Hz signal has a complete cycle of 20mS, You can display the value at each 1mS. This means that you will have to sample the data on each 100uS (total 10 samples --> 1mS). 100uS will be sufficient enough to convert all 4 channels. (Again, "Sample Timing Considerations" is very important).


    Please let me know if anything else is needed.

    Regards,

    Binoy.

  • EDIT:

    I didn't notice that your task is only to display the sine wave.

    To display the live data in your application, is it needed to take average? Or will it be better if you display the data directly following the conversion? If your idea is only to display the signal, you may try this as well.

    Regards,

    Binoy Raphael.

  • Hi Binoy,
    my goal is to calculate the instantaneous power and displayed on an LCD. In the pin 1.0 I will measure current using a CT sensor and the pin 1.3 I will measure the voltage. Those values must be average and for more samples of the signal, the greater the accuracy in the calculationsFor this issue had thought to use the DTC.
    I will modified my code to use TimerA (100 us, 10KHz), then I will sample the signal during 20 periods, calculates the power and display it in the LCD. All of this repeatedly.
     
    Regards.
  • Hi Federico,

    Then I guess you can utilize my code, which can be used for a number of channels and within a timer interrupt. Please let me know if you'll be interested.

    Also, are you using a 16x2 LCD module?

  • Hi Binoy,


    I'm interested in your code, of course. Examples always help.

    I´m using a I2C library for comunicate with 20x4 LCD-I2C (pins 1.6 and 1.7).

    Regards,

    Federico.

  • If you can place your email id here, I can send it to you.

    I'm not authorized to publish it in a public forum.

    Regards,

    Binoy Raphael.

  • email: fmontenegro430@gmail.com

  • Hi Federico,

    I've already sent it to you. Please let me know after you received & utilized it.

    Regards,

    Binoy Raphael.

  • Hi Binoy,


    I have not received any mail. Check the email: fmontenegro430@gmail.com


    Thanks.

  • Check my public mail in my profile.

  • Federico Montenegro said:
    I will decrease the stack size??

    It should be noted that there is no way to ‘set’ the stack size. The stack grows as the program flows. Each time you call a function, the stack grows. When an ISR is called, the stack grows. (and shrinks on return). If a function has local variables, the stack grows. (I’ve seen someone declaring an array of 512 INTs as local variable on an MSP with only 256 bytes of ram.)
    At compile/link time, neither compiler nor linker can know how large the stack will grow. It is the responsibility of the coder to estimate the required stack size. The ‘stack size setting’ in the project settings just puts aside this amount to ensure that at least so much is still available after all global variables are placed. But whether you set it to 0 or maximum, it won’t affect the running code and always the same binary is produced.

    BTW: it is possible to use a different memory are for storing values (like the INFO memory or even the main flash), but writing to them requires a special procedure, and is very slow.
    So it can be used for long-term logging, for storing a persistent counter, or for data that is updated seldom and used often.

  • thanks, I'll remember.

**Attention** This is a public forum