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.

MSP430 3 channels ADC

HI,

Can I use the 3 channels ADC inputs(A3,A4,A5) in MSP430, but the sampling rate of each three are different?

Thanks for your reply.

Best regards,

Steve.

  • Hi,

    What do you want exactly? Of course, you can start every conversion by software and implement different sampling rates. But which data rates do you want to achieve?

    Best regards
    Edwin Krasser

  • Hi, Steve,

    I'm gonna bounce your thread over to the MSP430 forum where hopefully more people will see it, and be able to give you advice.

    -d2

  • Like Edwin said, you can trigger the conversions at different rates using different sources (like three timers) the problem I see with that is, when the samplings collide with each other, as you cannot sample multiple channels at the same time (except you use a MSP with multiple ADC). So then you will get a deviation from your wanted sampling rate as every channel must be sampled in succession.

  • If sampling rates were Sr, 2Sr, 4Sr you could set an ad-hoc sequence of channels like A3-A4-A3-Ax-A3-A4-A3-A5.

    Then, after discarding Ax, you will get A3 sampled at 4Sr, A4 sampled at 2Sr and A5 sampled at Sr using a trigger at 8Sr.

    Regards,

    Peppe.

  • Hello,

    Thanks for your quickly reply.I discribe my problem more clear.

    Now I want to transmit three kind of analog signal to MSP430 simultaneously,each is heart sound (need 4KHz sampling rate) , ECG (need 1KHz sampling rate) and Pulse Oximetry signal (need  1KHz sampling rate).

    And do the AD converter to transmit these three signal via UART to PC , and use the PC to show this three signal simultaneously.

    How can I do this?

    Follow is the code I have , but I meet a problem to implement different A/D sampling rates to different input.In this code, I just have one timer source.

    Thanks for your further reply.

    Best regards,

    Steve.

    #include  <msp430x14x.h>

    int temp;

    void ADC_Init(void);

    void main(void)

    {  volatile unsigned int i;

      WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT

      BCSCTL1 |= XTS;                           // ACLK= LFXT1= HF XTAL

      do

      {

      IFG1 &= ~OFIFG;                           // Clear OSCFault flag

      for (i = 0xFF; i > 0; i--);               // Time for flag to set

      }

      while ((IFG1 & OFIFG));                   // OSCFault flag still set?

      BCSCTL2 |= SELM_3;                        // MCLK = LFXT1 (safe)

    //---------Set UART-------------------------------------------------------------

      P3SEL |= 0x30;                            // P3.4,5 = USART0 TXD/RXD

      ME1 |= UTXE0 + URXE0;                     // Enable USART0 TXD/RXD

      UCTL0 |= CHAR;                            // 8-bit character

      UTCTL0 |= SSEL0;                          // UCLK= ACLK

      UBR00 = 0x45;                             // 8MHz 115200

      UBR10 = 0x00;                             // 8MHz 115200

      UMCTL0 = 0xAA;                            // 8MHz 115200 modulation

      UCTL0 &= ~SWRST;                          // Initialize USART state machine

    //------------------------------------------------------------------------------

       ADC_Init();                               // Initialize ADC12

      ADC12CTL0 |= ENC;                         // Start conversion

      _EINT();

      while(1)

      {

        ADC12CTL0 |= ADC12SC;                   // Start conversion

      }

    }

     

     

    void ADC_Init(void)

    {

      P6SEL |= BIT3+BIT4+BIT5;                  // #Enable A/D channel A3,A4,A5

      P6DIR &=!(BIT3|BIT4|BIT5);

      ADC12CTL0 = ADC12ON+SHT0_1+MSC;           // Turn on ADC12, set sampling time

      ADC12CTL1 = SHP+CONSEQ_3+SHS_1;           // #Timer triggers sampling,Repeat-Sequence-of-Channels mode

      ADC12MCTL0 = INCH_3;                      // #Input channel select A3

      ADC12MCTL1 = INCH_4;                      // #Input channel select A4

      ADC12MCTL2 = INCH_5+EOS;                  // #Input channel select A5, end seq.

     

      ADC12IE = 0x01;                           // Enable ADC12IFG.0

     

      TACCR0 = 2000-1;                          //sampling rate : 8M / 2000 = 4KHz

      TACCR1 = 1000;

      TACCTL1 = OUTMOD_3;                       // Set/reset

      TACTL = TACLR | MC_1 | TASSEL_1;          // ACLK, clear TAR, up mode

    }

     

    // ADC12 Interrupt Service Routine

    #pragma vector=ADC_VECTOR

    __interrupt void ADC12ISR (void)

    {

      temp = ADC12MEM0 >> 4;

      while (!(IFG1 & UTXIFG0));            

      TXBUF0 = temp;

    }

     

  • Steve Chen89351 said:
    ...  I want to transmit three kind of analog signal to MSP430 simultaneously,each is heart sound (need 4KHz sampling rate) , ECG (need 1KHz sampling rate) and Pulse Oximetry signal (need  1KHz sampling rate)...

    One way to do that is as follows:

    1. You set up a Timer to generate interrupts at the rate of 8 kHz.

    2. In the Interrupt Service Routine, you count the interrupts modulo 8. That is, you count 0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7,0,1,2,3,....

    3. At each count of 0, 2, 4, or 6, you sample the heart sound.

    4. At each count of 1, you sample ECO.

    5. At each count of 3, you sample Oximeter signal.

    6. At each count of 5 or 7, you do not sample anything.

     

     

     

     

  • Hi,

    Well, 4 kHz and 2 times 1 kHz are needed. I think the best way is to setup a 4 KHz sampling. So, every 250 us a sequence of 3 conversion is started (triggered by a timer) and after finishing these 3 conversions your ISR is called. There you have got a modulo 4 counter running. Hence you can sort out every 4th value for your 1 KHz channels. That's it.

    Best regards and good luck
    Edwin Krasser

  • Hello,

    Thanks for your quickly reply.It's really useful.

    Can you show me how to write the code to do this?

    And I want to set below:

    ADC12MCTL0 = INCH_3;                      // #Input channel select A3

     ADC12MCTL1 = INCH_4;                      // #Input channel select A4

     ADC12MCTL2 = INCH_5+EOS;                  // #Input channel select A5, end seq.

    A3 is input of heartsound

    A4 is input of ECG

    A5 is input of  Pulse Oximetry signal

    Thanks for your reply.

    Best regards,

    Steve.

     

     

  • Hi,

    Because I am not doing MSP programming a lot (only a little, more C2000 stuff), I cannot realy help with the initializations of the ADC unit. But with the needed ADC-ISR. I suggest something like this:

    int FrameData[6];

    ... the #pragma stuff ...
    __interrupt void ADC_ISR(void)
    { static int Counter;
      Counter=(Counter+)&3; // Counter=0,1,2,3,0,1,2,3,0,...

      FrameData[Counter]= adc result 4 kHz channel ;
      if (Counter==0)
      { FrameData[4]= adc result first 1 kHz channel ;
        FrameData[5]= adc result second 1 kHz channel ;

      }
      if (Counter==3)
        ... copy the frame of 6 values to your transmit buffer ;

    }

    Then you will get every 1 ms a new transmit frame containing four values of the 4 kHz channel and the two 1 kHz channel values. I hope this helps.

    Best regards and good luck
    Edwin Krasser

  • Hi,

    Thanks for your reply. It's really useful.

    I write the code like below.Can anyone show me where is wrong?

    Can the TXBUF0 transmit the Framedata[6] one time sucessfully?

    ================================================================================================================

    #include  <msp430x14x.h>

    int temp;

    int FrameData[6];

    void ADC_Init(void);

    void main(void)

    {

      volatile unsigned int i;

     

      WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT

      BCSCTL1 |= XTS;                           // ACLK= LFXT1= HF XTAL

     

      do

      {

      IFG1 &= ~OFIFG;                           // Clear OSCFault flag

      for (i = 0xFF; i > 0; i--);               // Time for flag to set

      }

      while ((IFG1 & OFIFG));                   // OSCFault flag still set?

      BCSCTL2 |= SELM_3;                        // MCLK = LFXT1 (safe)

     

    //---------Set UART-------------------------------------------------------------

      P3SEL |= 0x30;                            // P3.4,5 = USART0 TXD/RXD

      ME1 |= UTXE0 + URXE0;                     // Enable USART0 TXD/RXD

      UCTL0 |= CHAR;                            // 8-bit character

      UTCTL0 |= SSEL0;                          // UCLK= ACLK

      UBR00 = 0x45;                             // 8MHz 115200

      UBR10 = 0x00;                             // 8MHz 115200

      UMCTL0 = 0xAA;                            // 8MHz 115200 modulation

      UCTL0 &= ~SWRST;                          // Initialize USART state machine

    //------------------------------------------------------------------------------

     

      ADC_Init();                               // Initialize ADC12

      ADC12CTL0 |= ENC;                         // Start conversion

     

      _EINT();

     

      while(1)

      {

        ADC12CTL0 |= ADC12SC;                   // Start conversion

      }

    }

     

     

    void ADC_Init(void)

    {

      P6SEL |= BIT3+BIT4+BIT5;                  // #Enable A/D channel A3,A4,A5

      P6DIR &=!(BIT3|BIT4|BIT5);

      ADC12CTL0 = ADC12ON+SHT0_1+MSC;           // Turn on ADC12, set sampling time

      ADC12CTL1 = SHP+CONSEQ_3+SHS_1;           // #Timer triggers sampling,Repeat-Sequence-of-Channels mode

      ADC12MCTL0 = INCH_3;                      // #Input channel select A3

      ADC12MCTL1 = INCH_4;                      // #Input channel select A4

      ADC12MCTL2 = INCH_5;                      // #Input channel select A5

     

      ADC12IE = 0x01;                           // Enable ADC12IFG.0

     

      TACCR0 = 2000-1;                          //sampling rate : 8M / 2000 = 4KHz

      TACCR1 = 1000;

      TACCTL1 = OUTMOD_3;                       // Set/reset

      TACTL = TACLR | MC_1 | TASSEL_1;          // ACLK, clear TAR, up mode

    }

     

    // ADC12 Interrupt Service Routine

    #pragma vector=ADC_VECTOR

    __interrupt void ADC12ISR (void)

    {

      static int Counter;

      Counter=(Counter+)&3; // Counter=0,1,2,3,0,1,2,3,0,...

     

      FrameData[Counter]= ADC12MEM0 ;

      if (Counter==0)

      { FrameData[4]= ADC12MEM1 ;

        FrameData[5]= ADC12MEM2 ; 

      }

      if (Counter==3)

       TXBUF0 = FrameData;         // ... copy the frame of 6 values to your transmit buffer 

    }

  • That won't work as the FrameData is an array of 6 values and TXBUF0 is only a single byte. You have to iterate through your array and send your data bytewise, your array is of the integer type, so it's 2 bytes per member.

    I'm not exactly sure what you will send over the line right now, my guess is the low part of the starting address of your array, definitely not what you want.

    So to give you an idea:

    for (int i = 0; i<6; i++) // iterate through the array
    {
        while (Busyflag & USART_Status) ; // wait until USART is ready
        TXBUF0 = (FrameData[i] >> 8); // send high part (MSB first)
         while (Busyflag & USART_Status) ; // wait until USART is ready  
          TXBUF0 = FrameData[i]; // send low part
    }

    I don't know the USART by head so I used some pseudo-flags and registers, but should be enough.

    Counter=(Counter+)&3; // Counter=0,1,2,3,0,1,2,3,0,...

    Is that legal C code and doing what's written? If so could someone with a higher understanding of C explain why it works? Or is there just the 1 missing after the +?

    I haven't checked all your code, just commented on the things which stood out for me.

  • Hi,

    you cannot copy the FrameData directly to your transmit buffer register because it's just a pointer to the array. But you can write the first byte of the frame buffer and start feeding the uart by an ISR.

    I would say something like this in the ADC ISR:

    if (Counter==3)
    { TXBUF=((unsigned char *)FrameData)[0];
      BytesAlreadyTransmitted=1;
      // enable the transmit interrupt for your uart at this place
    }

    And an UART ISR:
    ... UART TX ISR ...
    { TXBUF=((unsigned char *)FrameData)[BytesAlreadyTransmitted];
      BytesAlreadyTransmitted++;

      if (BytesAlreadyTransmitted>=12)
        // disable this uart transmit interrupt: transmission will stop!
    }

    Something like this should work. I think so.

    Best regards and good luck
    Edwin Krasser

  • Casting to a byte array is an elegant solution, I should think of something like that once in a while. But I guess coming from Java I try not to use the "evil" magic of C...

  • Bernhard Weller said:
    But I guess coming from Java I try not to use the "evil" magic of C...

    Well, Java has other means, but then, Java is not meant to run on limited resources.

    Re-interpreting data (e.g. an INT-array coming form here as a char array going to there)  is a common aproach. After all, the memory is a one-dimensional array of bytes, and interpreting things in this memory as something different than just bytes laying on a certain array index is just a matter of interpretation anyway.

  • Hi,

    Thanks for your reply.

    I see that doing the int casting to char would solve the transmit problem.

    Why when the BytesAlreadyTransmitted equal to 12 , then disable the transmission,

    does it need to be corrected to 6, because the size of  FrameData is 6. 

    Expect your further reply.

    Thanks very much.

    Best regards,

    Steve.

  • Hi,

    the length of the data buffer is 6 integers (equals 12 byte). Hence, you have to transmit 12 bytes.

    Best regards and good luck
    Edwin Krasser

**Attention** This is a public forum