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-ADC10: The Multiple Read From ADC10 for Any Possible PIN Selection

Part Number: MSP430-ADC10

Hi everyone !

This is my first issue on the forum. I am facing a problem on my robotic project with MSP430. So, i want to read ADC values from multiple pins on MSP. When i chose PIN0 for starting pin with PIN1, PIN2, PIN3, everything is okay, reading is okay, values are okay. Besides that i want to transfer these data with bluetooth module so i cannot use PIN1 and PIN2(PIN1 and PIN2 is reserved for UART communication). So, i modified the pin configurations and necessary register change and chose PIN0, PIN3, PIN4, PIN5 to read the ADC values but the code which is working before, didn't work. I am sharing the code below, if you faced this type of problem, please contact me. Thank you for your attention.

Best Regards

  • Hi Can,

    It doesn't look like your code was attached to the post. Can you reply with a simplified code snippet that repeats the issue you're experiencing? Also, which msp430 device variant are you running this code on?

    Best regards,
    Caleb Overbay
  • Hi Caleb,

    Sorry for carelessness. I am using MSP430 G2553 and I solve this problem by using single channel, single conversion mode for each PIN but nevertheless i am sharing first code which is not working and actually i want to know why it is not working or why msp430g2553 cannot measure the voltage from any PIN interval. Thank you for your attention Caleb !

    "The First Code That Does Not Work Properly"

    #include <msp430g2553.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <signal.h>

    unsigned int Voltage[4];

    void PIN_Config(void);
    void ADC_Config(void);
    void ADC_Reading(void);

    void main(void)
    {
    WDTCTL = WDTPW + WDTHOLD;

    PIN_Config();
    ADC_Config();

    while(1){
    ADC_Reading();
    _enable_interrupts();
    }
    }

    void PIN_Config(void){
    P1SEL = BIT1 | BIT2;
    P1SEL2 = BIT1 | BIT2;
    P1DIR = 0xF0;
    P1OUT &= ~0x00;
    P1IE |= 0x0F;
    P1IES |= 0x0F;
    P1IFG = 0x00;
    P2DIR = 0xFF;
    P2OUT &= ~0x00;
    }

    void ADC_Config(void){
    ADC10CTL1 = INCH_5+ CONSEQ_3;
    ADC10CTL0 = SREF_0 + ADC10ON + ADC10IE + MSC;
    ADC10DTC0 = ADC10CT;
    ADC10DTC1 = 0x4;
    ADC10AE0 |= 0x39;
    }

    void ADC_Reading(void){
    ADC10CTL0 &= ~ENC;
    while(ADC10CTL1 & BUSY);
    ADC10SA = (unsigned int)Voltage;
    ADC10CTL0 |= ENC + ADC10SC;
    }

    "The Second Code That Works Perfectly"

    #include <msp430g2553.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <signal.h>

    unsigned int X_Axis;
    unsigned int Y_Axis;
    unsigned int Z_Axis;
    unsigned int Gripper;

    void PIN_Config(void);
    void ADC_Config(void);
    void ADC_Reading_X_Axis(void);
    void ADC_Reading_Y_Axis(void);
    void ADC_Reading_Z_Axis(void);
    void ADC_Reading_Gripper(void);

    void main(void)
    {
    WDTCTL = WDTPW + WDTHOLD;

    PIN_Config();
    ADC_Config();

    while(1){
    ADC_Reading_X_Axis();
    ADC_Reading_Y_Axis();
    ADC_Reading_Z_Axis();
    ADC_Reading_Gripper();

    _enable_interrupts();
    }
    }

    void PIN_Config(void){
    P1SEL = BIT1 | BIT2;
    P1SEL2 = BIT1 | BIT2;
    P2DIR = 0xFF;
    P2OUT &= ~0x00;
    }

    void ADC_Config(void){
    ADC10CTL0 = SREF_0 + ADC10ON + ADC10IE;
    }

    void ADC_Reading_X_Axis(void){
    ADC10CTL0 &= ~ENC;
    ADC10CTL1 = INCH_0 + CONSEQ_0;
    ADC10AE0 |= BIT0;
    ADC10CTL0 |= ENC + ADC10SC;
    while(ADC10CTL1 & BUSY);
    X_Axis = ADC10MEM;
    }

    void ADC_Reading_Y_Axis(void){
    ADC10CTL0 &= ~ENC;
    ADC10CTL1 = INCH_3 + CONSEQ_0;
    ADC10AE0 |= BIT3;
    ADC10CTL0 |= ENC + ADC10SC;
    while(ADC10CTL1 & BUSY);
    Y_Axis = ADC10MEM;
    }

    void ADC_Reading_Z_Axis(void){
    ADC10CTL0 &= ~ENC;
    ADC10CTL1 = INCH_4 + CONSEQ_0;
    ADC10AE0 |= BIT4;
    ADC10CTL0 |= ENC + ADC10SC;
    while(ADC10CTL1 & BUSY);
    Z_Axis = ADC10MEM;
    }

    void ADC_Reading_Gripper(void){
    ADC10CTL0 &= ~ENC;
    ADC10CTL1 = INCH_5 + CONSEQ_0;
    ADC10AE0 |= BIT5;
    ADC10CTL0 |= ENC + ADC10SC;
    while(ADC10CTL1 & BUSY);
    Gripper = ADC10MEM;
    }

    #pragma vector = ADC10_VECTOR
    __interrupt void ADC10_ISR(void)
    {
    }

  • Hi Can,

    Can you be more specific about the issue the incorrect code is causing? Are you seeing bad values, no values, etc? Also, have you looked at the MSP430Ware examples for the MSP430G2553? Example msp430g2x33_adc10_14.c shows how to use repeat sequence of channels mode in a way that is very similar to what you are trying to accomplish. 

    Best regards, 
    Caleb Overbay

  • #include <msp430g2553.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <signal.h>

    unsigned int Voltage[4];

    void PIN_Config(void);
    void ADC_Config(void);
    void ADC_Reading(void);

    void main(void)
    {
    WDTCTL = WDTPW + WDTHOLD;

    PIN_Config();
    ADC_Config();

    while(1){
    ADC_Reading();
    _enable_interrupts();
    }
    }

    void PIN_Config(void){
    P1SEL = BIT1 | BIT2;
    P1SEL2 = BIT1 | BIT2;
    P1DIR = 0xF0;
    P1OUT &= ~0x00;
    P1IE |= 0x0F;
    P1IES |= 0x0F;
    P1IFG = 0x00;
    P2DIR = 0xFF;
    P2OUT &= ~0x00;
    }

    void ADC_Config(void){
    ADC10CTL1 = INCH_5+ CONSEQ_3;
    ADC10CTL0 = SREF_0 + ADC10ON + ADC10IE + MSC;
    ADC10DTC0 = ADC10CT;
    ADC10DTC1 = 0x4;
    ADC10AE0 |= 0x39;
    }

    void ADC_Reading(void){
    ADC10CTL0 &= ~ENC;
    while(ADC10CTL1 & BUSY);
    ADC10SA = (unsigned int)Voltage;
    ADC10CTL0 |= ENC + ADC10SC;
    }


    In this code, when PIN0, PIN1, PIN2, PIN3 are used as analog inputs(ADC10CTL1 = INCH_3+ CONSEQ_3 and ADC10AE0 |= 0x0F;), the values which are reading from ADC are right but when i change the input PINs as PIN0, PIN3, PIN4, PIN5 (ADC10CTL1 = INCH_5+ CONSEQ_3 and ADC10AE0 |= 0x39;), the values are incorrect such as sometimes bad values sometimes like no reading. Although the below code is a way to solve this problem and it is working very good, why the above code is not working, this is my question.

    #include <msp430g2553.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <signal.h>

    unsigned int X_Axis;
    unsigned int Y_Axis;
    unsigned int Z_Axis;
    unsigned int Gripper;

    void PIN_Config(void);
    void ADC_Config(void);
    void ADC_Reading_X_Axis(void);
    void ADC_Reading_Y_Axis(void);
    void ADC_Reading_Z_Axis(void);
    void ADC_Reading_Gripper(void);

    void main(void)
    {
    WDTCTL = WDTPW + WDTHOLD;

    PIN_Config();
    ADC_Config();

    while(1){
    ADC_Reading_X_Axis();
    ADC_Reading_Y_Axis();
    ADC_Reading_Z_Axis();
    ADC_Reading_Gripper();

    _enable_interrupts();
    }
    }

    void PIN_Config(void){
    P1SEL = BIT1 | BIT2;
    P1SEL2 = BIT1 | BIT2;
    P2DIR = 0xFF;
    P2OUT &= ~0x00;
    }

    void ADC_Config(void){
    ADC10CTL0 = SREF_0 + ADC10ON + ADC10IE;
    }

    void ADC_Reading_X_Axis(void){
    ADC10CTL0 &= ~ENC;
    ADC10CTL1 = INCH_0 + CONSEQ_0;
    ADC10AE0 |= BIT0;
    ADC10CTL0 |= ENC + ADC10SC;
    while(ADC10CTL1 & BUSY);
    X_Axis = ADC10MEM;
    }

    void ADC_Reading_Y_Axis(void){
    ADC10CTL0 &= ~ENC;
    ADC10CTL1 = INCH_3 + CONSEQ_0;
    ADC10AE0 |= BIT3;
    ADC10CTL0 |= ENC + ADC10SC;
    while(ADC10CTL1 & BUSY);
    Y_Axis = ADC10MEM;
    }

    void ADC_Reading_Z_Axis(void){
    ADC10CTL0 &= ~ENC;
    ADC10CTL1 = INCH_4 + CONSEQ_0;
    ADC10AE0 |= BIT4;
    ADC10CTL0 |= ENC + ADC10SC;
    while(ADC10CTL1 & BUSY);
    Z_Axis = ADC10MEM;
    }

    void ADC_Reading_Gripper(void){
    ADC10CTL0 &= ~ENC;
    ADC10CTL1 = INCH_5 + CONSEQ_0;
    ADC10AE0 |= BIT5;
    ADC10CTL0 |= ENC + ADC10SC;
    while(ADC10CTL1 & BUSY);
    Gripper = ADC10MEM;
    }

    #pragma vector = ADC10_VECTOR
    __interrupt void ADC10_ISR(void)
    {
    }
  • Hi Can,

    A few comments on the code that is not working properly:

    1. Try increasing the sample and hold time in ADC10CTL0.
      1. Try ADC10SHT_2
    2. I see you've enabled interrupts for the ADC but are not using them. When a conversion starts you need to give it enough time to take a full measurement. Reading the values before this could mean they are incorrect. Try waiting until the ADC interrupt flag is set before accessing the results or starting another conversion. An example of this can be found in the MSP430Ware example I referenced previously. 
    3. Finally, I highly suggest looking at the MSP430Ware example more closely. It does something very similar to what you are trying to accomplish here. 

    Best regards, 
    Caleb Overbay

  • Thank you for your attention again Caleb but i accomplished the problem using second code that i share above. Nevertheless the situation, that you mention your last comment which is related to incorrect reading, happened to me. In the below code i reading correct values from Y, Z and Gripper but X is not correct. I guess ADC has not enough time to measure the correct value but this is only happen for X (which is measured first). How can i fix it? I have "while(ADC10CTL1 & BUSY);" line before every conversion. Is not it enough? Besides i am receiving "Isr16.asm" warning while code is running sometimes. What does it mean and how can i fix it? As a last thing, what did you mean with "I see you've enabled interrupts for the ADC but are not using them." ? Thank you for your response again.

    #include <msp430g2553.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <signal.h>

    int X_Axis;
    int Y_Axis;
    int Z_Axis;
    int Gripper;

    void PIN_Config(void);
    void Time_Config(void);
    void UART_Config(void);
    void ADC_Config(void);
    void ADC_Reading_X_Axis(void);
    void ADC_Reading_Y_Axis(void);
    void ADC_Reading_Z_Axis(void);
    void ADC_Reading_Gripper(void);

    void main(void)
    {
    WDTCTL = WDTPW + WDTHOLD;

    PIN_Config();
    Time_Config();
    UART_Config();
    ADC_Config();

    while(1){
    ADC_Reading_X_Axis();
    ADC_Reading_Y_Axis();
    ADC_Reading_Z_Axis();
    ADC_Reading_Gripper();

    _enable_interrupts();
    }
    }

    void PIN_Config(void){
    P1SEL = BIT1 | BIT2;
    P1SEL2 = BIT1 | BIT2;
    P2DIR = 0xFF;
    P2OUT &= ~0x00;
    }

    void Time_Config(void){
    DCOCTL = 0;
    BCSCTL1 = CALBC1_1MHZ;
    DCOCTL = CALDCO_1MHZ;
    }

    void UART_Config(void){
    UCA0CTL1 |= UCSSEL_2;
    UCA0BR0 = 104;
    UCA0BR1 = 0;
    UCA0MCTL = UCBRS_1;
    UCA0CTL1 &= ~UCSWRST;
    IE2 |= UCA0TXIE;
    }

    void ADC_Config(void){
    ADC10CTL0 = SREF_0 + ADC10ON + ADC10IE;
    }

    void ADC_Reading_X_Axis(void){
    ADC10CTL0 &= ~ENC;
    ADC10CTL1 = INCH_0 + CONSEQ_0;
    ADC10AE0 |= BIT0;
    ADC10CTL0 |= ENC + ADC10SC;
    while(ADC10CTL1 & BUSY);
    X_Axis = ADC10MEM;
    UCA0TXBUF = X_Axis;
    }

    void ADC_Reading_Y_Axis(void){
    ADC10CTL0 &= ~ENC;
    ADC10CTL1 = INCH_3 + CONSEQ_0;
    ADC10AE0 |= BIT3;
    ADC10CTL0 |= ENC + ADC10SC;
    while(ADC10CTL1 & BUSY);
    Y_Axis = ADC10MEM;
    UCA0TXBUF = Y_Axis;
    }

    void ADC_Reading_Z_Axis(void){
    ADC10CTL0 &= ~ENC;
    ADC10CTL1 = INCH_4 + CONSEQ_0;
    ADC10AE0 |= BIT4;
    ADC10CTL0 |= ENC + ADC10SC;
    while(ADC10CTL1 & BUSY);
    Z_Axis = ADC10MEM;
    UCA0TXBUF = Z_Axis;
    }

    void ADC_Reading_Gripper(void){
    ADC10CTL0 &= ~ENC;
    ADC10CTL1 = INCH_5 + CONSEQ_0;
    ADC10AE0 |= BIT5;
    ADC10CTL0 |= ENC + ADC10SC;
    while(ADC10CTL1 & BUSY);
    Gripper = ADC10MEM;
    UCA0TXBUF = Gripper;
    }

    #pragma vector = ADC10_VECTOR
    __interrupt void ADC10_ISR(void)
    {
    ADC10MEM = (ADC10MEM >> 7);
    }

    #pragma vector=USCIAB0TX_VECTOR
    __interrupt void USCI0TX_ISR(void)
    {
    IE2 &= ~UCA0TXIE;
    }

  • Hi Can,

    All of my previous comments were to answer your question of why your first "non-working" set of code was failing. I still recommend trying to accomplish this task with a sequence of conversions instead of the single channel approach you've created. The single channel approach will take a much longer time to execute.

    Now to answer your question as to why the X reading on the single channel approach is not working. Why are you shifting the ADC10MEM register in the ADC ISR? I suspect this is the cause of your issue. It seems to serve no purpose in the code and if the ISR executes before ADC_Reading_XXXX() it will corrupt your results. The approach you're using with "while(ADC10CTL1 & BUSY);" is a polling implementation and does not require the use of interrupts. If you don't intend to use ADC interrupts, you should disable them in the AADC10CTL0 register.  Also, try increasing the sample and hold time to 8 ADC clock cycles from the 4 that you currently have it set to.

    Finally, please take a look at the ADC code examples provided in MSP430Ware. They show the proper use of interrupts for an application just like this one.

    Best regards,

    Caleb Overbay

  • Hi Caleb,

    First of all, i studied the MSP430 Ware ADC examples but there was any problem which is using different PIN selections such as my project. It has used just PIN0 and PIN1 so it's used consecutive PIN selection. When i connect PINs consecutively, my code is working well, too.

    So, after read your comments, i made some changes in the other code; removed the ADC_ISR, disabled interrupts and increase SHT up to 8 in ADC10CTL register but same problem is still contiuning. ADC is passing to the Y_Axis just before finish the X_Axis reading. And i also tried some "while(ADC10CTL1 & BUSY);" lines in the code but i didn't make it correct. Most probably, i could not place "while(ADC10CTL1 & BUSY);" to the correct line.

    In addition, i really want to accomplish this task with repeat sequence of multi channels but before doing this, i have to prepare a preview until the first deadline date. After doing this part, i will send these data to the MSP432 with bluetooth module and i will drive 4 motors with these data using MSP432. Actually, i prepared a trial code for receiver part but i cannot try before transmitter part competely ends. So, if i make a good preview, i can change the ADC part with Repeat Sequence Multi Channels conversion until second deadline. This is why i prefer easy way to do this quickly. :)

    Best Regards
  • Hi Can,

    Using the following code I am not seeing the issue you're describing. When experiencing the issue are you looking at the X_Axis, Y_Axis, etc variables in the debugger of CCS or are you trying to view them via the terminal? I haven't debugged your UART code but from a quick glance I see there could be possible issues there as well.

    #include <msp430.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <signal.h>
    
    int X_Axis;
    int Y_Axis;
    int Z_Axis;
    int Gripper;
    
    void PIN_Config(void);
    void Time_Config(void);
    void UART_Config(void);
    void ADC_Config(void);
    void ADC_Reading_X_Axis(void);
    void ADC_Reading_Y_Axis(void);
    void ADC_Reading_Z_Axis(void);
    void ADC_Reading_Gripper(void);
    
    void main(void)
    {
        WDTCTL = WDTPW + WDTHOLD;
    
        PIN_Config();
        Time_Config();
        UART_Config();
        ADC_Config();
    
        while(1)
        {
            ADC_Reading_X_Axis();
            ADC_Reading_Y_Axis();
            ADC_Reading_Z_Axis();
            ADC_Reading_Gripper();
            _enable_interrupts();
        }
    }
    
    void PIN_Config(void){
        P1SEL = BIT1 | BIT2;
        P1SEL2 = BIT1 | BIT2;
        P2DIR = 0xFF;
        P2OUT &= ~0x00;
    }
    
    void Time_Config(void){
        DCOCTL = 0;
        BCSCTL1 = CALBC1_1MHZ;
        DCOCTL = CALDCO_1MHZ;
    }
    
    void UART_Config(void){
        UCA0CTL1 |= UCSSEL_2;
        UCA0BR0 = 104;
        UCA0BR1 = 0;
        UCA0MCTL = UCBRS_1;
        UCA0CTL1 &= ~UCSWRST;
        IE2 |= UCA0TXIE;
    }
    
    void ADC_Config(void){
        ADC10CTL0 = SREF_0 + ADC10ON + ADC10SHT_1;
    }
    
    void ADC_Reading_X_Axis(void){
        ADC10CTL0 &= ~ENC;
        ADC10CTL1 = INCH_0 + CONSEQ_0;
        ADC10AE0 |= BIT0;
        ADC10CTL0 |= ENC + ADC10SC;
        while(ADC10CTL1 & BUSY);
        X_Axis = ADC10MEM;
        UCA0TXBUF = X_Axis;
    }
    
    void ADC_Reading_Y_Axis(void){
        ADC10CTL0 &= ~ENC;
        ADC10CTL1 = INCH_3 + CONSEQ_0;
        ADC10AE0 |= BIT3;
        ADC10CTL0 |= ENC + ADC10SC;
        while(ADC10CTL1 & BUSY);
        Y_Axis = ADC10MEM;
        UCA0TXBUF = Y_Axis;
    }
    
    void ADC_Reading_Z_Axis(void){
        ADC10CTL0 &= ~ENC;
        ADC10CTL1 = INCH_4 + CONSEQ_0;
        ADC10AE0 |= BIT4;
        ADC10CTL0 |= ENC + ADC10SC;
        while(ADC10CTL1 & BUSY);
        Z_Axis = ADC10MEM;
        UCA0TXBUF = Z_Axis;
    }
    
    void ADC_Reading_Gripper(void){
        ADC10CTL0 &= ~ENC;
        ADC10CTL1 = INCH_5 + CONSEQ_0;
        ADC10AE0 |= BIT5;
        ADC10CTL0 |= ENC + ADC10SC;
        while(ADC10CTL1 & BUSY);
        Gripper = ADC10MEM;
        UCA0TXBUF = Gripper;
    }
    
    
    #pragma vector=USCIAB0TX_VECTOR
    __interrupt void USCI0TX_ISR(void)
    {
        IE2 &= ~UCA0TXIE;
    }

    Best regards, 
    Caleb Overbay

  • Hi Caleb,

    Of course, i am checking them in the debugger, Expressions window. If i summarize my project, i have 2 axis 2 joy stick module which have 0V to 3.3V output with feeding MSP430 Vcc and i made some calibrations to easily control the motors which MSP432 will drive, so this is why i used bit shifting. This gives me a value from 0 to 7 for each axis. If it is 0, it means that the axis output is 0V or ADC10MEM value is 0; if it is 7, it means that the axis output is 3.3v or ADC10MEM is 1023.  Unfortunately, although all axis except X_Axis gives 7 or 1023 or 3.3V when bring them to the their maximum positions, X_Axis cannot reach the its maximum value. I am sharing screenshot of debugger window and the values. Besides, the UART section is working i guess, and i am checking UCA0TXBUF in the registers window but if you are thinking something is wrong, please share to me.

    Best Regards

    Above figure's values on the right are related to central position joy stick module. While three axis are giving 4, the X_Axis is 3. Below figure's values are related to maximum position of joy sticks and as it can be seen, X_Axis is 6 and the others are 7.

  • Hi Can,

    I apologize for the delayed response as I've been out a few days. Now that you've described why the shift is present, I think I'm understanding your issue a little better. Let's first tackle the UART code.

    When you take an ADC measurement, you immediately put the result into TXBUF. I recommend checking the TX interrupt flag before writing anything to this buffer. By checking this first, you are ensuring that you're not overwriting something that is in the buffer that hasn't been sent yet. Adding while(IFG2 & UCA0TXIFG); before writing to the buffer should do the trick. Also, I see you've enabled TX interrupts in UART_Config() with the line IE2 |= UCA0TXIE; but then disable them when you get into the ISR with the line IE2 &= ~UCA0TXIE;. The approach you've taken here doesn't require interrupts so you could simply disable UART interrupts and remove the ISR from your code. Again here, I have to refer you to MSP430Ware with UART examples that show best practices. 

    Finally, I'm still not seeing the ADC results you are. With the same code and applying VCC to X_Axis, I am consistently getting the expected result of 7 after shifting ADC10MEM right by 7. There could be several factors that are causing this difference in measurement. Section 22.2.5.1 of the user's guide for the MSP430G2553 provides a formula to calculate the minimum sampling time. Please review it and see if you are meeting this specification for the X_Axis input.

    Best regards, 

    Caleb Overbay

  • Hi Caleb,

    I am very sory for late responce again. The uncorrect measurement which I mentioned in above replies, is based on the LED that is internally connected to PIN0. When i removed the jumper between PIN0 and the LED, the measurement gave me better and correnct result. Thank you for your all attention again. I am so grateful.
  • Hi Can,

    Glad to hear there was a simple solution. Thanks for updating your post to let us know!

    Best regards,
    Caleb Overbay

**Attention** This is a public forum