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.

MSP430G2553: ADC10 sampling issue

Part Number: MSP430G2553

Hi team,

Here's an issue from the customer may need your help:

A 2-kHz sinusoidal signal is generated with a 1-v amplitude from the signal source, then the signal is acquired through ADC10 of the MSP430G2553, and the acquired data is sent via UART to the matlab for waveform restoration. But the recovered signal always has a glitch (sometimes it's OK). The customer would like to know is there anything wrong with the program? (The signal from the source is accurate and has been tested).

The following figure shows two conditions for glitches:

Normal is as the following figure:

#include <msp430.h>
#include "stdint.h"


#define nn 100;
uint16_t adcbuff[100] = {0}; //An array of nn lengths
uint8_t combuff[20]={0}; //Used to save the commands accepted by the serial port
uint8_t iscomend =0 ;//End of command? Used to determine if a complete command has been received successfully
/**
* main.c
*/
void InitSystemClock(void)
{
DCOCTL = CALDCO_16MHZ;
BCSCTL1 = CALBC1_16MHZ;
BCSCTL2 &= ~SELS; //Select the source of SMCLK
BCSCTL2 &= ~(DIVS0 | DIVS1); //Set the division factor
}

void InitUART(void)
{
UCA0CTL1 |= UCSWRST; //set UCSWRST
//Initialize all UCSI registers
UCA0CTL0 &= ~(UCMODE1 | UCMODE0); //Configure UCSI mode 00 to UART mode
UCA0CTL0 &= ~UCSYNC; //Select asynchronous mode
UCA0CTL1 |= (UCSSEL1 | UCSSEL0); //Configure clock sources 10 and 11 as SMLCK

//Configure the baud rate, look at UCOS16, and then look in the user manual for table 15.4 UCBRx UCBRSx UCBRFx The last two are actually in UCAxMCTL
UCA0BR0=0x82;
UCA0BR1=0x06;
UCA0MCTL |= (UCBRS1| UCBRS2);
//Configure the port
P1SEL |= BIT1 + BIT2;
P1SEL2 |= BIT1 + BIT2;
//Clear reset to enable UART
UCA0CTL1 &= ~UCSWRST;

IE2 |= UCA0RXIE; //Turn on the receive interrupt of the serial port
IFG2 &= ~UCA0RXIFG ;// Clear the receive interrupt flag
}

void InitADCTrigByTimerA(void)
{
ADC10CTL1 |= ADC10SSEL_2;//Select the clock source


ADC10CTL1 |= SHS0; //Select Timer A out1 SHSx for sampling and hold source 01 for Timer_A out1 00 for ADC10SC bit
ADC10CTL1 |= CONSEQ1; //Select conversion sequence 00 to single-channel single-conversion 01 to channel sequence

ADC10CTL0 |= SREF_1;//Set the reference, external or internal?
ADC10CTL0 |= ADC10SHT_1; //Set the ADC10 sample hold time to 16 CLK

ADC10CTL0 &= ~ADC10SR; //ADC10 sample rate

ADC10CTL0 |= REF2_5V; //ADC reference selection 2.5 V
ADC10CTL0 |= REFON; //Turn on the reference

ADC10CTL1 |= INCH_4;//Select the ADC input channel A4

ADC10AE0 |= 1 << 4;//Allows A4 analogue input

//DTC transfer mode
ADC10DTC0 |= ADC10CT;//At 1, the data is transmitted continuously, and the operation of the DTC only stops when ADC10CT is cleared or ADC10SA is written

ADC10DTC1 = nn; //The total number of transfers is 50

ADC10SA = (uint16_t)(adcbuff); //ADC10SA to determine the start address, which forces the first address of adcbuff to a 16-bit integer

/*turn on ADC*/
ADC10CTL0 |= ADC10ON;

/*Allow conversion */
ADC10CTL0 |= ENC;

}

void InitTimerA()
{
TA0CTL |=TASSEL1; //Configure the clock bit SMLCk
TA0CTL |= MC0; // Up mode, 01 is up, and up is up to TA0CCR0, 10 is continuous mode and the timer counts to 0FFFFh
//11 Up/Down mode is the timer increases to TACCR0 and then decreases to 0000h
TA0CCR0 =0x004F;// configure TA0CCR0 bit 0x004F
TA0CCR1= 0x002F;//set duty cycle (TACCR0-TACCR1)/TARRC0 At this time, the duty cycle is 1/2, frequency = SMCLK/(TACCR0+1)/2 SMCLK is set in the clock. For example, 16 MHz/80/2 is approximately 100 k, approximately the sampling frequency, and the maximum sampling frequency
TA0CCTL0 &= ~CAP;
TA0CCTL1 &= ~CAP;
TA0CCTL1 |= OUTMOD_6;
//Set IO multiplexing
P1SEL |= BIT6;//
P1DIR |= BIT6;//

}

int main(void)
{
uint16_t cnt = 0;

WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer
InitSystemClock();
InitUART();
InitADCTrigByTimerA();
InitTimerA();
__bis_SR_register(GIE);//Turn on global interrupts

while(1)
            {
               if(iscomend)
                 {
                   iscomend =0; 
                   for(cnt = 0; cnt<100;cnt ++)
                        { 
                               while(UCA0STAT & UCBUSY);
                              UCA0TXBUF=*(adcbuff+cnt)/256; //The data in adcbuff is sent out, 8 bits high first
                              __delay_cycles(30000); 
                              while(UCA0STAT & UCBUSY);
                             UCA0TXBUF=*(adcbuff+cnt)%256; //And then 8 bits lower
                             __delay_cycles(30000);
                          }

                }
            }
return 0;
}

#pragma vector = USCIAB0RX_VECTOR
__interrupt void UART_Receive_ISR(void)
{
            static uint8_t cnt2 = 0;
            if(IFG2 & UCA0RXIFG)//Detects if the receive interrupt is USCI_A0, and the receive interrupt shares the same amount for USCI_A0 and USIC_B0
                {
                    IFG2 &= ~UCA0RXIFG;//Clear the flag bit
                     combuff[cnt2++] = UCA0RXBUF;//Save the command
                    cnt2 %= 20;//Prevents cnt greater than 20, causing buffer overflow
                     if(combuff[cnt2 - 1] == '#')//If a command end character is detected (end of command with '#')
                           {
                               cnt2 = 0;//Reset the counter
                               iscomend = 1;//Command received
                           }
                }
}

Note: It's equivalent to using the G2553 as an oscilloscope.

Could you help check this case? Thanks.

Best Regards,

Cherry

  • Hi,

    The glitch on the signal seems periodically. It looks like the noise is coming from the power supply. Check the MCU VCC and use an external voltage reference for the ADC if possible.

    Best regards,

    Cash Hao

  • > TA0CCR0 =0x004F;// configure TA0CCR0 bit 0x004F

    This will trigger the ADC at (16MHz/80)=200ksps, i.e. a sample every 5usec. (If the X-axis of those charts is "sample number", I see 10 samples per signal cycle, which for a 2kHz signal indicates a sample rate of 20ksps, not 200ksps. Is this the code you're actually using?)

    > UCA0BR0=0x82;
    > UCA0BR1=0x06;

    This configures the UART for (16MHz/1666)=9600bps. At this speed sending one sample (2  bytes) takes about 2msec, during which time the ADC (DTC) will store (200*2)=400 samples. . The UART will not be able to keep up. The effect is that main() is reading adcbuff while the DTC is updating it, which is presumably the cause of the glitches.

    If you want to capture a 2kHz signal, you'll need to speed up the UART quite a bit, and probably slow down the ADC.

    To support a 200ksps rate, the UART needs to sustain (2bytes*10bits*200ksps)=4Mbps. The data sheet maximum is 2Mbps [Ref data sheet (SLAS735J) p. 33, first table]. I've never succeeded in going faster (reliably) than about 500kbps in a G2-series device (using the DCO).

    Unsolicited: Using a 16MHz clock for the ADC10 is far out of spec [Ref data sheet (SLAS735J) p. 39, middle table]. I suggest you use ADC10OSC (ADC10SSEL=0).

  • I don't think that the difference between sample rate and bit rate is a problem.

    The ADC is used to capture 50 values, once. The data is not sent until the required command is received over the UART. (The UART really ought to be configured with UCOS=1 given the large difference between input clock and bit rate.)

    The ADC clock derived from SMCLK is clearly beyond its maximum. But switching to ADC10OSC may not work since the conversion time may be slower than the timer triggers.

  • With ADC10CT=1 (continuous), the UART code will (always) be reading the buffer as it is being written by the DTC, which is an invitation to glitches. As you suggest,, one way to fix this is to use ADC10CT=0 and restart the DTC after each fetch is completed (burst mode).

    With SHT=2 and a 5MHz clock, each sample will take (16+13)/5MHz=5.8 usec, which will indeed overrun the 5usec trigger period. But running it with a (much) faster clock is out of spec, which is why I suggested slowing down the ADC (trigger rate). It would actually succeed with a 6MHz ADC10CLK (and a fast-enough MCLK), but it may not be easy to derive such a clock on a G2-series.

    There are various ways this code could evolve, and it's probably not useful for me to guess which way the OP prefers.

  • Hello Cash, Bruce and David,

    Thanks a lot for your support! And may I know which answer is the best choice for me to update to the end customer?

    Thanks and Best Regards,

    Cherry

  • Hi Cherry,

    You can let the customer try lower the ADC sampling frequency first. If they still observe the glitch, try to isolate the noise then.

    Best regards,

    Cash Hao

  • Leave ADC10CT=0 and restart the DTC (by setting ADC10SA) at the end of the if(iscomend) block.

    Longer term, set ADC10SSEL=0 and lower the sample rate a little —maybe TA0CCR0=100-1 or so.

  • Hi Cash and Bruce,

    Thanks for your clarification and help! 

    Best Regards,

    Cherry

**Attention** This is a public forum