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.

MSP430F6769A: Regarding improving accuracy of A/D conversion

Part Number: MSP430F6769A
Other Parts Discussed in Thread: MSP-TS430PEU128

Hi,

Thank you as always!

I am currently writing code to improve the accuracy of a 24-bit ΔΣ ADC.

Currently I am looking at the output of AD conversion using the Resource Explorer sample code msp430f677xA_sd24b_06.c.

Currently, supply voltage = 3.3V, referenc voltage = 1.25V (external), input voltage = 1.0V are input.

With almost no changes to the program, we were able to achieve performance with approximately 14 bits or less. However, it does not perform as well as described.

 I have a question here.

・What code should I use to increase the OSR to 1024? I set SD24BOSRx to OSR=9, but the result is 27 times the usual value? It has risen to about.

・What code is used to perform AD conversion? Is this done with SD24BISR? I can't see the inside of SD24BISR from this program and it's confusing.

・I wanted to use IQmathlib, so I got the library and included it, but how should I write this program for AD conversion?

MSP430 IQmathLib Users Guide version 01.10.00.05 User's Guide

https://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/IQmathLib/latest/exports/MSP430-IQmathLib-UsersGuide.pdf

I read it, but I didn't know how to use it.

I am using MSP-TS430PEU128 and inserting a pin header to input the voltage. The 3.3V power supply voltage is also input externally.

I would appreciate it if you could let me know if you have any other ideas that could improve accuracy.

I would appreciate it if you could give me some advice since I am ignorant.

Thank you.

Toshiharu

  • Hi Toshiharu,

    1. For setting the OSR to 1024 fill the whole register so SD23BOSRx = 0x3FF
    2. The SD24BCCTLx register contains where you control conversions.
      1. SD24SCSx bit allows for different options including external triggers, group triggers, or setting the start conversion bit
      2. SD23SC is the start conversion bit
      3. Example code
    3. For IQ math you will want to convert the result of the ADC conversion into an IQ number using the _IQN (float A) function then perform math functions using IQ math variable types. See the User's Guide for more information

    Aside from software digital filters, having a good analog front end can help improve results. Our Implementation of a 3-phase Electronic Watt-hour Meter provides some examples for analog front end. Though the intended input signal is 120v @ 60Hz or 240V @50 Hz (typical power lines around the world).

    Regards,
    Luke

  • Hi, Luke

    Thank you for answering!

    I have set only the parts that I understand.

    1.When I set the SD23BOSRx register to 0x3FF, the 6bit value (64 times) increased as shown in the image. Do you know the cause?

    2.I had already seen the code example and was currently doing the conversion with that code. SD23SC is the conversion start bit, but does it also apply to conversion operations?

    3.It was unclear which function to use and which value to substitute when executing an IQ math function. Regarding question 2, I think it can be used if you know the AD conversion function formula and the value to substitute, but I would like to know that.

    I apologize for my ignorance.

    if you'd kindly teach me.

    Thank you.

    Toshiharu

  • Hi, Luke

    I'll change the reply slightly.

    3.I made a program like this.This program is a modification of what Luke taught me.

    I'm measuring on ch0.

    But the result remained the same.

    Are you still using it incorrectly?

    #define GLOBAL_IQ 24 
    #include <msp430.h>
    #include<iqmathlib.h>

    float results;
    _iq24 IQ_results;

    void main(void){

    void main(void)
    {

      WDTCTL = WDTPW | WDTHOLD; 

      SD24BCTL0 = SD24SSEL_1 | SD24DIV4; 

      SD24BINCTL0 = SD24GAIN_1 | SD24INTDLY0; 

      SD24BCCTL0 = SD24SNGL | SD24DF1; 

      SD24BIE |= SD24IE0;  

      SD24BOSR0 |= 0x3FF; 

      __delay_cycles(0x3600); 

      while (1)
      {
       SD24BCCTL0 = SD24SC; 
       __bis_SR_register(LPM0_bits | GIE); 
       __no_operation();
       __no_operation(); 
      }

    }

    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector=SD24B_VECTOR
    __interrupt void SD24BISR(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(SD24B_VECTOR))) SD24BISR (void)
    #else
    #error Compiler not supported!
    #endif
    {

     switch (SD24BIV)
     {
       case SD24BIV_SD24OVIFG: 
         break;
       case SD24BIV_SD24TRGIFG: 
         break;
       case SD24BIV_SD24IFG0: 
         IQ_results = _IQ24(results);
         IQ_results = SD24BMEMH0;
         IQ_results = (IQ_results << 16) | SD24BMEML0;
         break;
       case SD24BIV_SD24IFG1: // SD24MEM1 IFG
         break;
       case SD24BIV_SD24IFG2: // SD24MEM2 IFG
         break;
     }

     __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0

    }

     

    Thank you,

    Toshiharu

  • Hi Toshiharu,

    In your ISR under the SD24BIV_SD241FG0 case, I believe the order here is wrong.

    unsigned long results;
    _iq24 IQ_results;
    ...
    case SD24BIV_SD24IFG0:   
        results = SD24BMEMH0;
        results = (results << 16) | SD24BMEML0;
        IQ_results = _IQ24(results);
        break;
    ...

    Between the 2 tests you made using the formula. Voltage = Code * VREF / Max Code

    256 OSR (Default) - Max value is FF FFFF (16777216)

    Recorded Value - 15072365

    Voltage = 15072365 * 1.25 / 16777216 = 1.123 (rounded to nearest thousandths)

    -------

    1024 OSR - Max Value is 4000 0000 (1073741824)

    Recorded Value - 964826962

    Voltage = 964826962 * 1.25 / 1073741824 = 1.123 (rounded to nearest thousandths)

    ------

    As for why the value is 64x greater, this is due to the formula to create the full scale range. FS = 2^(3*log2(OSR)), the full scale range with an oversampling of 1024 is 64 times greater than the full scale range of the default 256 oversampling.

    Another check is to divide the full scale ranges to get their ratio. 1073741824/16777216 = 64.

    When setting the SC bit, it will start sampling and conversion, when the whole process is finished it will generate the interrupt. IQMath can be used to create the actual voltage value like I did in my math above. Or if you're creating statistics like Vrms, Irms, Power etc. IQMath can help with the large multiplications and divisions.

    Regards,
    Luke

  • Hi, Luke

    Thank you very much! My understanding of OSR has deepened!

    But a problem arose.

     unsigned long results;
    _iq24 IQ_results;
    ...
    case SD24BIV_SD24IFG0:
    results = SD24BMEMH0;
    results = (results << 16) | SD24BMEML0;
    IQ_results = _IQ24(results);
    break;
    ...

    When I changed the program above, the value of IQ_results changed greatly.

    Please see the image for details.

    Does this mean that results will be a float type and the result will be _IQ24(results)?

    However, due to my lack of knowledge, even if I change it to a float type,

        results = (results << 16) | SD24BMEML0;

    If you set it to float type, it will not be able to build because of this statement. I don't know how to change it. 

    I'm sorry for not telling you all the time, but I would like to receive your knowledge.

    Thank you.

    Toshiharu

  • Hi Toshiharu,

    The compiler is probably stating that you can't do a bitwise operation on a floating point number. Floats and IQMath have different representations than integers, so bitwise functions won't give the proper result. After further investigation, I don't think we will need to use the float data type here.

    You can directly cast the Results to an IQ24 Number. 

    int32_t results;
    _iq24 IQ_results;
    ...
    case SD24BIV_SD24IFG0:
    //Get and store results from the ADC
    results = SD24BMEMH0;
    results = (results << 16) | SD24BMEML0;
    IQ_results = (_iq24) (results >> 8);

    To see the value of IQMath right click in the expressions window then go to Q values and select the Q-value that corresponds to the IQMath number. 

    -----

    Another design decision would be the type of math that you will be using. You may need to use different IQ types to prevent overflow, and this would require you to do some right shifts.

    To do conversion between your IQMath number to a decimal you can do the inverse operation of what is listed in the IQMath User's Guide.

    Inverse Operation would be 2^n * Xiq = Xi. For example if we take the number you have: 964826962. Store it as an IQ24, we would do an 8-bit right shift then cast as an iq24 our result is Xiq = 0.2246412635. To get back to our original number we would take the 0.2246412635 * 2^24 then left shift 8.

    I recommend testing different operations and conditions, as you want to prevent an overflow of data during your expect application use case.

    Regards,
    Luke

  • When I changed the program above, the value of IQ_results changed greatly.

    Of course it did. When you convert an integer to IQ24 format you shift it left 24 bits. This aligns the binary point of your integer with the binary point of the IQ24 format.  Resulting in 24 bits of your result vanishing. Including 16 of the 24 bits of the ADC result.

    That conversion works a lot better if you start with something suitable. Like a float.

    Better would be to apply your scaling factor to the ADC result then switch to IQ24. It could in fact be done in one step. Assuming you have a scale factor in IQ24 format, just multiply. No need to use the IQmath functions, just a regular multiply.

    Since you start with a number with zero fractional bits and one with 24, the result will have 24 and thus be in IQ24 format. Assuming the scale factor doesn't result in an overflow of the integer part, this works great. If it does overflow, you need a different IQ format.

  • Hi, Luke

    Thank you for answering !

    Sorry for the late reply. Also, I still have questions.

    I was able to express the IQ value as you said.
    For the calculation results, look at the user guide and change the N value to see the numerical values.
    Let's change the program to find out various conditions and operations for overflow.
    If you have any questions about conditions or operations, please feel free to contact us.
    Now I have a question.
    You may need to use different IQ types to prevent overflow

    Does this mean that the N value of IQN must be accurate?

    For example, in the case of an ADC with 24-bit resolution, the good condition is IQ24, but if IQ28 or IQ16, it will be inconvenient.

    Thank you

    Toshiharu

  • Hi, David

    Thank you for answering !

    Is it correct to understand that if you try to obtain a 24-bit value for IQ24, it will be shifted 24 bits to the left and as a result you will not be able to obtain a 16-bit ADC value?

    I'm currently trying to make the Q value appropriate by multiplying Results by an appropriate scaling factor.

    The current situation is the default offset binary state, and I have confirmed the output around 964827590, but even if it is doubled, it will immediately reach 16777216.

    In this case, will it be an IQN (IQ5 or less) that will not reach 16777216 even if it is doubled?

    I apologize for my lack of knowledge.

    I would appreciate it if you could let me know.

    Thank you

    Toshiharu

  • Hi, David

    Sorry, I didn't have enough information.

    Supplement.
    In this case, will it be an IQN (IQ5 or less) that will not reach 16777216 even if it is doubled?

    Regarding this, when I looked at the user guide (page 10, Table 2.2: IQmath Data Types), the MAX of _iq7 was 16,777,215... so I thought it would be less than 1/2, _iq5.

    https://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/IQmathLib/latest/exports/MSP430-IQmathLib-UsersGuide.pdf

    Thank you

    Toshiharu

**Attention** This is a public forum