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.

Continuous Data Acquisition with MSP430G2553

Hi everyone, 

I am attempting to setup a continuous data acquisition routine with the MSP430, it will transmit the integers over UART to be read and interpreted by MATLAB. I intend to operate at a sample rate of above 10Khz. I have read a few previous articles on this website and was able to set up continuous data transmission, however I observed some irregularities and I am not sure of the cause. I am not sure I have gone about this in the best way also my knowledge of operating the ADC on the MSP430 is not extensive, but I am aware of the functions of the majority of registers. 

// Main Routine
#include "msp430G2553.h"
#include "Config.h"
#include "Initialise.h"
#include "UARTSend.h"
 
void ConfigureTimerAPWM(void);
void ConfigureADCBlock(void);
void ConfigureUART(void);
void InitialisePorts(void);
void UARTSendArray(unsigned char *TxString, unsigned int ArrayLength);
void UARTSendIntArray(unsigned int *TxArray, unsigned int ArrayLength);
void UARTSendTerminator(void);
 
volatile unsigned int data[SAMPLES]; // define data array

void main(void)
{
  InitialisePorts();
  ConfigureUART();
  ConfigureTimerAPWM();
  //ConfigureADCBlock();
  __enable_interrupt(); // Enable interrupts.
  __bis_SR_register(LPM0_bits + GIE); // Enter LPM0, interrupts enabled
}
 
// Echo back RXed character, confirm TX buffer is ready first
#pragma vector=USCIAB0RX_VECTOR
__interrupt void USCI0RX_ISR(void)
{
  if (UCA0RXBUF == 'D') // If it recieves char D it will start
  {
    UARTSendArray("Sending data\n\r", 14);
    P1OUT |= BIT0; // Turn on RED to indicate start of conversion
    
    ADC10CTL0 &= ~ENC;
    ADC10CTL0 = ADC10ON;
    
    ADC10CTL1 = INCH_5 + SHS_0 + ADC10DIV_3 + ADC10SSEL_3 +CONSEQ_2 ; // Select input channel 5. Sample and hold source (0: ADCSCbit). ADC10CLK Divider (0: /1). ADC Clock source (0: internal 5MHz oscillator). Repeat single channel
    ADC10AE0 |= BIT5; // Enable P1.5 as ADC input

    while(ADC10CTL1 & ADC10BUSY);
      P1OUT ^= BIT0;
      ADC10DTC0 = ADC10CT; // Continuous Transfer mode
      ADC10DTC1 = 255;
      ADC10SA = data;
      
      ADC10CTL0 = SREF_0 + ADC10SHT_1 + MSC + ADC10ON + ADC10IE; // Reference Voltage (0: Vcc & Vss). Sample and hold time (0: 4 ADC clk cycles). Enable continous sampling. Turn ADC on. Enable ADC interrupt
      
      ADC10CTL0 |= ENC + ADC10SC; // ADC Sampling and conversion start
      
  } // end of if Statement
}
     
// ADC10 interrupt service routine
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR (void)
{
  //ADC10CTL0 &= ~ENC; // Switch off conversion
  UARTSendArray(data,2*SAMPLES); // sends the data it has recorded 
  P1OUT &= ~BIT0; // Turn off LED1 to indicate transmission complete
  //volatile unsigned int data[SAMPLES]; // define data array    
}

// Initialising Clock on MSP

void InitialisePorts(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
BCSCTL1 = CALBC1_16MHZ; // Set DCO to 16MHz
DCOCTL = CALDCO_16MHZ;
P1DIR |= BIT0; // Set the LED on P1.0 outputs
P1OUT &= ~BIT0; // Turn on LED1 to indicate start of conversion
}

One potential change I could make is to allow the MSP430 to receive the number of acquisitions the user would like to make over UART, so it does not have to continuously cycle, this will allow both devices to know what to send and expect. This may also speed up interpretation in MATLAB.

// MATLAB Code, the number of data acquisitions to occur is defined by the input parameter x,
Nstring = 14;
Nintdata = 248*x;
obj=serial('COM8','BaudRate', 9600,'Terminator', 'LF/CR','InputBufferSize',2*Nintdata+Nstring);
fopen(obj);
finishup = onCleanup(@() fclose(obj));

command = 'D';
fprintf(obj,command); % Send D down the UART
string = fscanf(obj,'%c',14);
disp(['Response: ' string(1:end-2)])
disp(' ');
 
if strcmp(string(1:end-2),'Sending data'),
    %pause(0.2); % watch out 
    data = fread(obj,Nintdata,'uint16');
    N=length(data);
    disp([num2str(N) ' integers received']);
    Fs = 10e3/0.044;
    time = (0:N-1)./Fs;
    figure(1);
    plot(time,data);
    xlabel('Time (s)');
    ylabel('Amplitude');
    grid on; 
    y = data;
end

The irregularities I observe is that my sample rate is significantly slower, about 500Hz down by a factor of 100, I have tried playing around with the clock divider but it doesnt make a difference even though when I had my code to do a single acquisition it worked just fine. Additionally in MATLAB it takes a while to process the information I suspect it is due to not receiving the data on time or the data sent over UART is not cleaned correctly. When the data is obtained the plot comes out a bit strange the first 248 samples (first acquisition) is just fine in terms of magnitude and accuracy. However when the next acquisition is made the magnitude is completely incorrect (10^4). It will then return to the correct magnitude and accuracy on the next 248 bits. This occurs on an odd even basis. Again I know the problem is either in the memory of the ADC not been cleared correctly after it has sent, I  tried re declaring the data array but it doesn't make a difference. Or in the reading of the integers sent over UART in MATLAB. 

  •  Hi, I think you (and too many come to these fora) need a lot of homework to study how serial communication work and also what is the bandwidth needed by a channel to transmit sustained 10K sample of 12 bit require two bytes so your bandwidth get half Byte rate..

     But bit rate is set to 9600 Baud.. where you think you can go with half BIT rate than two time needed BYTE rate?

     Get a good book and try grasp how serial communication/ protocols are working due you need account not only data flow so at least 38400/57600 are good theoretical bit rate  speed...

     Your problem is unrelated to MSP430 this forum is dedicated to.

  • Roberto, he's probably using the G2LaunchPad (G2553 smells like) and the application UART, so 9600Bd is the max he can use.

    However,
    with 9600Bd, a maximum of 960 bytes is sent per second. With two bytes per sample, you won't get more than 480 samples sent per second, no matter how fast the ADC gets the samples or how fast you fill the buffer.
    Also, you're wasting additional time by first filling the buffer (in which time you don't send) and then sending the buffer (in which time you don't sample). So your data transmission is not continuous, and your intended (and probably achieved) ADC sampling rate of 10kH won't get you anywhere if you can't send the sampled values in the same time you get them.

    As Roberto already said: this is not an MSP problem but a problem of general math and common sense.
  • Jens-Michael Gross said:
    with 9600Bd, a maximum of 960 bytes is sent per second. With two bytes per sample, you won't get more than 480 samples sent per second, no matter how fast the ADC gets the samples or how fast you fill the buffer.

     Hi Michael, I bet for a much much lower rate, program was tossing out a lot of string data useful for human understanding and require some megabits to transfer all bytes generated from single sample too.

     On TIVA forum I insisted to split forum as we can better serve a beginner helping grow up and ask all it need. TI insist leave burden on specialized forum.

     What can I say? Sometimes beginner start bad wording and persecution to what they cannot understand...

     We can ask again @BLAKE what it think about, my opinion is I cannot waste time and get offended and persecuted so I left TIVA forum alone and switched away from TI cortex too in favour of competitor.

  • Roberto - The TI E2E Community is open to anyone from just getting started to advanced. Separating Forums into beginner or advanced is not something that will be done. As the TI and MSP Community continues to grow we will continue to welcome everyone here and do our best to get them what they need.

    When addressing other Community members please leave out words like "newbie" or "beginner" especially when doing so in an intimidating or demeaning manner (it may not seem that way but that is how it comes across). This only generates negative non-constructive situations to arise and takes a Forum thread off topic quickly. At times we will have periods where Community members might forget or not immediately realize to search first for solutions and patience is required to help orient them to the resources they have available. Each day let us all work hand in hand to continue to make the TI and MSP Community a vibrant and rich one of knowledge sharing.

  •  In first congratulations to Jeans in its special day.

    Blake Ethridge said:
    When addressing other Community members please leave out words like "newbie" or "beginner" especially when doing so in an intimidating or demeaning manner (it may not seem that way but that is how it comes across).

     Hi Blake, I think this is the problem and cannot be simply left this way.

     New processor MSP432 let all of us newbye and beginner me too (We don't know nothing about so learning curve is at origin). On a startup new user area can benefit all wish collect hint without searching a tons of information useful but unrelated.

     This is the better way a split can be useful, MSP CPU are completely different, 432 is a Cortex, peripheral at my first look appear to be same as old MSP, so all knowledge can be really shared in a more simple way than having just one big container saturated with all and nothing. Cortex is non sense to MSP and reverse.

     So clearly thematic areas can help find information about some peripheral and or special code.

     Having special area where c programming problem can be posted can help leave specialized forum free of unnecessary posts and yes in that area poster ask help for programming not special library or peripheral and forum avoid get noisy...
     Maybe I am wrong, but my idea is you can state we can teach same classroom of undergraduate basic algebra and same time complex analytical function infinitesimal calculus? Undergraduate cannot understand convolution product and college one get annoyed of basic algebra.. is not this the useless way?

    Blake Ethridge said:
    Each day let us all work hand in hand to continue to make the TI and MSP Community a vibrant and rich one of knowledge sharing.

     I find knowledge sharing discussing about decimation filter, delta sigma converter and all MSP feature but not so much of how to multiply two integer number or how to change one line of html code...
     I think who need start learn everything is necessary to use a microcontroller need get some idea of prerequisites but I see this is your point of view, you are the responsible of this forum and this is last time I try ask...

  • Hi Everyone,

    Thank you for all the replies.

    Admittingly I didn't consider the baud rate, as I normally disregard it since I always require lower sample rates than this. However in this application I would still like to achieve the maximum possible sample rate and transmission over a serial interface with my MSP device.

    Also I have not looked at this project for a while, but I am considering revisiting it to try and achieve my objectives.

    Regardless I think this project would be worth it, since I will be able to measure a signal and transmit it in real time directly to MATLAB. Additionally it would be good if when executing the script, the duration of the entire sample could be specified. Example:

    StartSampling(10) // this would be within MATLAB, it would send a notifier down the serial interface this would be interpreted by the MSP consequently sampling for only this specific interval of time (10 secs) and then returning to sleep mode. maybe another parameter to set the sampling rate may also be beneficial.

    I believe the functional blocks of this project should be as follows:

    [Wake from Sleep] - > [Receive sample rate and sample time from UART] -> [Set timers and ADC accordingly and begin sampling] -> [Send data over UART + a handshaking bit ] -> [at the end of sampling send the stop bit] -> [enters sleep mode]

    What I do not know how to do is to sample from the ADC at a specific frequency and transmit it at the same time over UART. This would be by far my greatest difficulty. I feel getting this all to work with such perfect timing is a great challenge for me as I generally do not have to work on such strict time parameters. 

    Regarding the baud rate of 9600, would I be correct in saying this is the number of symbols which can be sent per second? If this is the case then the maximum sample rate assuming each data value occupies one symbol is 9.6Khz. 

    Thank you for reading this.

    Regards, Jarez

  • Jarez Patel said:
    What I do not know how to do is to sample from the ADC at a specific frequency and transmit it at the same time over UART.


    You can use a timer to start each individual ADC conversion. When the conversion is done, the ADC can trigger an interrupt . In the ISR you can start the transmission of the result.
    Since a result is 10 bit and an UART byte is 8 bit, you need to send two bytes per conversion. Or you reduce the result to 8 bit. In the first case, if the USCI is idle (that means baudrate is higher than required data rate), you can write both bytes to TXBUF right after another. The first will immediately start sending, while the second will stay in TXBUF until the first is sent. But this requires that the UART is idle (else the first byte would wait in TXBUF and the second will overwrite/replace it).

    Regarding baudrate, this is the maximum number of BITS that are sent per second, including the organizational start and stop bits.
    so for each 8 data bits, two bits are added for start and stop. Then umber of bytes you can send per second is baudrate/10. And only if you send them in time.
    How many symbols you can send depends on the size of the symbols. An ADC result is 10 bit. So unless you pack them somehow, sending it takes 2.083 ms (2* 1.041ms).
    So your max data rate is 480Hz for 10 bit values or 960Hz for 8 bit values.

    You may pack your data. You may start with an assumed value of 0, and only send 4 bit per value indicating whether the next value is 8 (or more) higher or lower than the last. this limits your large signal response but allows you to double the sampling rate for small signal response.
    The old SoundBlaster digital audio standard (*.VOC files) used this method (actually only 2 bits per sample) to compress audio data. Here the highest energy components (the largest amplitude changes) are usually low frequency while the high frequencies have just a small amplitude. Sending difference values has significantly reduced file size.

    An alternative is to not use the application UART at all. The 9600Bd limitation is caused by the TUSB chip on the LaunchPad (it requires its main transmission power for the PC/FET communication for debugging - the application UART is just a bonus effect of unused processing power) and not by the MSP itself.
    You can attach any USB/UART converter to the MSP. Preferably one with direct TTL compatible 3.3V signal levels (most will produce RS232 signals to mimic a COM port).
    In this case, your baudrate can be as high as 115200Bd or even 230400Bd. But with the G2553 not supporting a high-speed crystal, the quality of the factory calibrated clock frequencies is critical for those high baudrates.

    If you know the limitations, it is not really difficult to put things together. Start with low sample rates and then increase the speed. You'll see when your code starts failing (usually before the theoretical limit) and you can start refining it to get as close as possible to the theoretical limit. But this limit exists and must not be ignored. Everything takes time. Even though a microsecond seems to be nothing for a human, it easily sums up to more time that you have if you want sampling rates in the kHz range etc.

**Attention** This is a public forum