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.

MSP4305529 float conversion

Other Parts Discussed in Thread: MSP430F5528

I am using the MSP4305529's  12 bit ADC to acquire voltage readings. 8 samples are taken then averaged by a SCALE_FACTOR of 3. The result is then stored in sum_adc_data. 

sum_adc_data >>= SCALE_FACTOR;

I wanted to output the value as a voltage, so we stored the value in vout. In order to get the correct voltage we multiplied by the appropriate ADC12_RATIO (2500/4095).

 vout = sum_adc_data * ADC12_RATIO;

the problem is that when I check the registers in CCS vout does not give me the appropriate value. I decided to just copy the value from the sum_adc_data to vout.

 vout = sum_adc_data ;

 I still obtained the same result for vout. Below I have provided the code and a screenshot of the registers:

#include <msp430.h> 
#include <stdint.h>
#include "TI_LMP91000.h"
#include "TI_LMP91000_register_settings.h"
#include "TI_MSP430.h"
#include "TI_MSP430_hardware_board.h"
#include "TI_MSP430_i2c.h"

/*----------------------------------------------------------------------------*/
void ADC12_Init(void);                                                         // To init MSP430F5528 ADC12 & Start Conversion
/*----------------------------------------------------------------------------*/
#define NUM_OF_RESULTS  8                                                      // Number of temp sensor samples to take
#define SCALE_FACTOR    3                                                      // For averaging converted samples
#define ADC12_RATIO     0.61035                                                // 2500/4096 (2.5V reference & 12bit converter)
//******************************************************************************
void main(void)
{

  uint8_t status = TI_LMP91000_NOT_READY;
  uint8_t read_val[2];                                                         // buffer to store register values

  WDTCTL = WDTPW + WDTHOLD;                                                    // Stop watchdog timer

  TI_LMP91000_LED_PxOUT |= TI_LMP91000_LED_PIN;                                // Set LED ON
  TI_LMP91000_LED_PxDIR |= TI_LMP91000_LED_PIN;                                // Set pin direction is output

  I2CSetup(LMP91000_I2C_Address);                                              // Initialize I2C module

  TI_LMP91000_MENB_PxOUT &= ~TI_LMP91000_MENB_PIN;                             // Enable \MENB Pin
  TI_LMP91000_MENB_PxDIR |= TI_LMP91000_MENB_PIN;                              // Set pin direction is output

  while (status == TI_LMP91000_NOT_READY)
    status = LMP91000_I2CReadReg(TI_LMP91000_STATUS_REG);                      // Read device ready status

  LMP91000_I2CWriteReg(TI_LMP91000_LOCK_REG, TI_LMP91000_WRITE_UNLOCK);        // unlock the registers for write

  LMP91000_I2CWriteReg(TI_LMP91000_TIACN_REG, TI_LMP91000_TIACN_REG_VALUE);    // Modify TIA control register
  LMP91000_I2CWriteReg(TI_LMP91000_REFCN_REG, TI_LMP91000_REFCN_REG_VALUE);    // Modify REF control register

  read_val[0]   = LMP91000_I2CReadReg(TI_LMP91000_TIACN_REG);                  // Read to confirm register is modified
  read_val[1]   = LMP91000_I2CReadReg(TI_LMP91000_REFCN_REG);                  // Read to confirm register is modified

  if ((read_val[0] != TI_LMP91000_TIACN_REG_VALUE) ||
      (read_val[1] != TI_LMP91000_REFCN_REG_VALUE))                            // test values took effect
    while (1);                                                                 // otherwise error

  LMP91000_I2CWriteReg(TI_LMP91000_LOCK_REG, TI_LMP91000_WRITE_LOCK);          // lock the registers
  LMP91000_I2CWriteReg(TI_LMP91000_MODECN_REG, TI_LMP91000_MODECN_REG_VALUE);  // 3-lead amperometric cell

  ADC12_Init();                                                                // Initialize MSP430F5528 ADC12 & Start Conversion
  __bis_SR_register(LPM0_bits + GIE);                                          // Enter LPM0, Enable interrupts
  __no_operation();                                                            // For debugger

}

// Description: Initialization of the ADC12 Module & Start Conversion
/*----------------------------------------------------------------------------*/
void ADC12_Init(void)
{
  TI_LMP91000_VOUT_ADC12_PxSEL |= TI_LMP91000_VOUT_ADC12_PIN;                  // Enable A/D channel A0
  REFCTL0 &= ~REFMSTR;                                                         // Reset REFMSTR to hand over control to
                                                                               // ADC12_A ref control registers
  ADC12CTL0 = ADC12ON+ADC12SHT0_8+ADC12MSC;                                    // Turn on ADC12, set sampling time
                                                                               // set multiple sample conversion
  ADC12CTL0 |= ADC12REFON+ADC12REF2_5V;                                        // Turn on Ref Gen & set to 2.5V
  ADC12MCTL0 = ADC12SREF_1;                                                    // Vr+ = Vref+ and Vr- = AVSS
  ADC12CTL1 = ADC12SHP+ADC12CONSEQ_2;                                          // Use sampling timer, set mode
  ADC12IE = ADC12IE0;                                                          // Enable ADC12IFG.0
  __delay_cycles(500);                                                         // delay to allow Ref to settle
  ADC12CTL0 |= ADC12ENC;                                                       // Enable conversions
  ADC12CTL0 |= ADC12SC;                                                        // Start conversion

}
/*----------------------------------------------------------------------------*/
// Description:
//   ADC12 Interrupt Service Routine 
/*----------------------------------------------------------------------------*/

#pragma vector=ADC12_VECTOR
__interrupt void ADC12ISR (void)
{
  static uint8_t index = 0;
  static volatile uint16_t results[NUM_OF_RESULTS];                            // To store ADC output
  static uint32_t sum_adc_data = 0;                                            // accumulate and avg adc results
  static volatile float vout;                                                  // lmp91000 vout

  switch(__even_in_range(ADC12IV,34))
  {
  case  0: break;                                                              // Vector  0:  No interrupt
  case  2: break;                                                              // Vector  2:  ADC overflow
  case  4: break;                                                              // Vector  4:  ADC timing overflow
  case  6:                                                                     // Vector  6:  ADC12IFG0
    results[index] = ADC12MEM0;                                                // Move results
    sum_adc_data += ADC12MEM0;
    index++;                                                                   // Increment results index, modulo;

    if (index == NUM_OF_RESULTS)
    {
      sum_adc_data >>= SCALE_FACTOR;                                           // Divide by NUM_OF_RESULTS
      vout = sum_adc_data * ADC12_RATIO;                                       // LMP91000 vout
      sum_adc_data = 0;                                                        // Set Breakpoint here & see measured vout
      index = 0;
    }
    break;
  case  8: break;                                                              // Vector  8:  ADC12IFG1
  case 10: break;                                                              // Vector 10:  ADC12IFG2
  case 12: break;                                                              // Vector 12:  ADC12IFG3
  case 14: break;                                                              // Vector 14:  ADC12IFG4
  case 16: break;                                                              // Vector 16:  ADC12IFG5
  case 18: break;                                                              // Vector 18:  ADC12IFG6
  case 20: break;                                                              // Vector 20:  ADC12IFG7
  case 22: break;                                                              // Vector 22:  ADC12IFG8
  case 24: break;                                                              // Vector 24:  ADC12IFG9
  case 26: break;                                                              // Vector 26:  ADC12IFG10
  case 28: break;                                                              // Vector 28:  ADC12IFG11
  case 30: break;                                                              // Vector 30:  ADC12IFG12
  case 32: break;                                                              // Vector 32:  ADC12IFG13
  case 34: break;                                                              // Vector 34:  ADC12IFG14
  default: break;
  }
}

here are the results when we multiply with the ADC12_RATIO:

here are the results when the ratio is removed

shouldn't my vout have the same value as sum_adc_data since all i did was assign the value to vout? Is there a problem with float types in the msp430? How can I fix this issue?

  • I'm not sure what is happening within your code but in general I would avoid floating point operations on the MSP430 as they are very expensive. What I would do instead would be to change the math to support fixed point mulitplication and division. You can do so by changing your vout line to:

    "vout = (sum_adc_data * 2500) / 4095;"

    and declaring vout as an int. You will still lose some accuracy when dividing by the "4095" because it will be truncated but this is a much more efficient implementation given the use of the MSP430 controller.

    You can also check out this document for how to best perform multiplicaiton and division operations within the MSP430:

    http://www.ti.com/lit/an/slaa329/slaa329.pdf

     

    Matt

  • Greetings Matt,

    First of all thank you for the quick response! The data sheet reads:

    The MPY32 supports:
    • Unsigned multiply
    • Signed multiply
    • Unsigned multiply accumulate
    • Signed multiply accumulate
    • 8-bit, 16-bit, 24-bit, and 32-bit operands
    • Saturation
    Fractional numbers
    • 8-bit and 16-bit operation compatible with 16-bit hardware multiplier
    • 8-bit and 24-bit multiplications without requiring a "sign extend"
    the msp4305529 has dedicated hardware for multiplication, so multiplying should produce a plausible value.

    vout = sum_adc_data * ADC12_RATIO            //  ADC12_RATIO  is    0.6103

    However, I still attempted the method you advised and I obtained the following results

    this is still not accurate..I should obtain 1.67 Volts or 1670 mV in the vout register.

    If you could assist me with the troubleshooting I would greatly appreciate it; thank you for the help!

    Regards,

    Jonathan

  • Jonathan Velez said:
    this is still not accurate..I should obtain 1.67 Volts or 1670 mV in the vout register.

    Try vout as 32bit integer.

  • I noticed that in all of your screen shots, the address of your variable "vout" is at 0x004400. Isn't that Flash memory?

    -OCY

  • old_cow_yellow said:
    I noticed that in all of your screen shots, the address of your variable "vout" is at 0x004400. Isn't that Flash memory?

    0x004400 is indeed the start of flash in a MSP430F5528. The other thing I notice from the screen shots is that both the vout and results variables are reported at the same address of 0x004400.

    If the problem occurs using a MSP430 compiler v4.2.x and an output format of "eabi (ELF)" then it might be the same problem I reported in CCS 5.5 debugger shows incorrect address for C++ class given static storage allocation in main. The problem in the referenced thread was that the CCS debugger was unable to correct resolve the address of variables from the debug information generated by the compiler.

  • The attached project also shows the problem, with the static variables from the ISR function placed in main. 7635.msp430_statics_in_main.zip. It was generated in CCS 5.5 with MSP430 compiler v4.2.3 set to an output format of "eabi(ALF).

    In the debugger the following screen shot shows the index and sum_adc_data variables have been correctly resolved to their address in RAM, but the results and vout variables have both been resolved to the incorrect address of 0x004604 in flash (which is the address in flash of main):

    When the expression view was used to cast the RAM address where the vout variable really is (from the linker map file) the correct value was displayed. i.e. the floating point calculation has been performed correctly on the target and the problem is that the CCS debugger is not displayed the correct value of the vout (and results) variables.

  • First of all, thank you all for the time and help; I greatly appreciate it! Chester I referenced your post regarding the compiler error and by changing the compiler to V 4.2.1 and the output file to legacy COFF I was able to get the correct output value for vout.

    Thanks!

    Best regards,

    Jonathan

**Attention** This is a public forum