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.

CCS/MSP430FR5969: INA250 output to MSP430FR5969 Integrated 12b ADC problem

Part Number: MSP430FR5969
Other Parts Discussed in Thread: INA250

Tool/software: Code Composer Studio

Hello,

The goal of my project is to make a programmable current sink from 0-1A using the PWM from the MSP430 and the intergrated 12 b ADC to complete the control loop.

I have recently been able to recreate my simulation (attached) and my code below to output the correct voltage on my INA250 to measure the current throught my load resistor.

I have a question regarding reading the voltage from the INA250 to my ADC. When I run the code independently with an external DC power supply, the ADC is able to read the voltage on the pin.

Though when I connect the output of the INA 250 EVM to the input of the ADC (verified the voltage is correct using a DMM), the voltage is incorrect in ADCMEM0.

Pasted is my code as well as my TINA simulation for the external circuitry.

#include <msp430.h>

float ADC_val;
int Current_add;
float Voltage_Desired;
float Current_Set;
float Current_t;
float Duty_Cycle;
float Current_val;
int PWM_up;

float Voltage_val ;
float ADC(void)
{
WDTCTL = WDTPW | WDTHOLD; // Stop WDT

// GPIO Setup
P4OUT &= ~BIT6; // Clear LED to start
P4DIR |= BIT6; // Set P1.0/LED to output
P1SEL1 |= BIT5; // Configure P1.1 for ADC
P1SEL0 |= BIT5;

// Disable the GPIO power-on default high-impedance mode to activate
// previously configured port settings
PM5CTL0 &= ~LOCKLPM5;

// Configure ADC12
ADC12CTL0 = ADC12SHT0_2 | ADC12ON; // Sampling time, S&H=16, ADC12 on
ADC12CTL1 = ADC12SHP; // Use sampling timer
ADC12CTL2 |= ADC12RES_2; // 12-bit conversion results
ADC12MCTL0 |= ADC12INCH_5; // A1 ADC input select; Vref=AVCC
ADC12IER0 |= ADC12IE0; // Enable ADC conv complete interrupt

while (1)
{
__delay_cycles(5000);
ADC12CTL0 |= ADC12ENC | ADC12SC; // Start sampling/conversion


__bis_SR_register(LPM0_bits | GIE); // LPM0, ADC12_ISR will force exit
__no_operation(); // For debugger

}

}


int main(void)
{
WDTCTL = WDTPW | WDTHOLD; // Stop WDT

// Configure GPIO
P1DIR |= BIT0 | BIT1; // P1.0 and P1.1 output
P1SEL0 |= BIT0 | BIT1; // P1.0 and P1.1 options select

// P1IES |= 0x00;

// Disable the GPIO power-on default high-impedance mode to activate
// previously configured port settings
PM5CTL0 &= ~LOCKLPM5;

CSCTL0_H = CSKEY >> 8; // Unlock CS registers
CSCTL1 = DCOFSEL_6; // Set DCO = 8MHz
CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK;// Set ACLK=VLO SMCLK=DCO
CSCTL3 = DIVA__2 | DIVS__2 | DIVM__2; // Set all dividers
CSCTL0_H = 0; // Lock CS registers

// Configure Timer0_A
TA0CCR0 = 2000; // PWM Period
TA0CCTL1 = OUTMOD_7; // CCR1 reset/set
TA0CCR1 = 666; // CCR1 PWM duty cycle

TA0CCTL0 = CCIE ; // CPC intetupt


TA0CTL = TASSEL__SMCLK | MC__UP | TACLR; // SMCLK, up mode, clear TAR

//__bis_SR_register(LPM0_bits); // Enter LPM0

ADC();

}

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = ADC12_VECTOR
__interrupt void ADC12_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(ADC12_VECTOR))) ADC12_ISR (void)
#else
#error Compiler not supported!
#endif
{
switch(__even_in_range(ADC12IV, ADC12IV_ADC12RDYIFG))
{
case ADC12IV_NONE: break; // Vector 0: No interrupt
case ADC12IV_ADC12OVIFG: break; // Vector 2: ADC12MEMx Overflow
case ADC12IV_ADC12TOVIFG: break; // Vector 4: Conversion time overflow
case ADC12IV_ADC12HIIFG: break; // Vector 6: ADC12BHI
case ADC12IV_ADC12LOIFG: break; // Vector 8: ADC12BLO
case ADC12IV_ADC12INIFG: break; // Vector 10: ADC12BIN
case ADC12IV_ADC12IFG0: // Vector 12: ADC12MEM0 Interrupt


Current_Set = .03125
;

Voltage_Desired = Current_Set *2;
ADC_val = ADC12MEM0;
Voltage_val = (ADC_val*3.6)/4096;
Current_val = Voltage_val/2;
Duty_Cycle = (Voltage_val*2000)/3;

if (Voltage_val != Voltage_Desired)
{
Duty_Cycle = (Voltage_Desired*2000) / 3;
}
else
{
Duty_Cycle = TA0CCR1;
}

TA0CCR1 = Duty_Cycle;
}

}
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer0_A0_ISR (void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(TIMER0_A0_VECTOR))) Timer0_A0_ISR (void)
#else
#error Compiler not supported!
#endif
{
if (PWM_up == 1)
TA0CCR1 = x;
PWM_up = 0;


}

SALLEN_KEY_W_FET - autosave 19-10-08 16_18 - autosave 19-10-10 08_33 - autosave 19-10-11 08_34.TSC

Thank you for the support!

Connor Connaughton

  • Hi Connor

    You can use our demo code to see if the ADC can get the correct result like this one http://dev.ti.com/tirex/explore/node?node=AM6OnzaAOO6rktD8QJ1WwQ__IOGqZri__LATEST

    You can measure the voltage first by a multimeter.

    Dose the output of the INA 250 EVM is stable? Could you measure it by a oscilloscope?

    Best regards

    Gary

  • How do you know that the voltage is incorrect? Are you measuring at the pin, or using the debugger?

    I don't have a copy of TINA here, so I can't comment on the schematic. But it looks as though you're using the ADC as feedback to set a certain PWM output.

    As coded, this program will do only one ADC sample (ever), since I don't see a wakeup to allow main to request a second one.

    There's also a "!=" comparison between two float-s, which is pretty much guaranteed to be true. As a result, the PWM duty will be set based on a constant (0.3125) to 2% (about 70mV),, where it will stay since there won't be any more ADC samples. I suppose(?) that this will change the actual voltage at the pin.

    I suspect this isn't how you intended this to work, but I'm not sure what to suggest since I don't know what all the constants mean.

  • Bruce,

    Thank you for the reply.

    I have been measuring with an oscilloscope at the pin of where I am reading my ADC (Pin 1.5) and then reading ADCMEM0 for my ADC decimal value where I convert to a readable voltage by doing (3.6*ADC)/4096.

    You are correct, I have to create a simple control loop that takes in the ADC voltage from the INA 250 and change the duty cycle respectively depending on what voltage I set.

    Can you clarify what "not seeing a wakeup" means for the ADC?

    As for comparing too floats, yes thank you I will correct this. The reason I compared the floats was to ensure I can get for example 1.75V input to the ADC and convert it to its respective duty cycle.

     

    Variable definitions:

    Current_Set = Setting the current I want out to the load resistor

    Voltage_Desired = Actual voltage needed

    ADC_val = ADC12MEM0;

    Voltage_val = (ADC_val*3.6)/4096 = Voltage coming into ADC

    Current_val = Voltage_val/2;

    Duty_Cycle = (Voltage_val*2000)/3;

    Please let me know if you have any additional questions.

    Thank you for the support!

    Connor Connaughton

  • I would expect to see, in your ADC ISR, something like "LPM0_EXIT" to wake up ADC(). Otherwise it will sit there in LPM forever, and never start another ADC conversion. 

    What voltage do you measure at the pin, and what value do you see in MEM0?

    Unsolicited: You're doing a fair amount of floating-point arithmetic in the ISR, which means nothing else will run for (estimating) a few 10s of milliseconds. Currently, your program doesn't have anything else to do, so it isn't getting in your way. But as you add to the program this won't scale well. I suggest you move the arithmetic to ADC().

  • Bruce,

    Thank you! I added __bic_SR_register_on_exit(LPM0_bits); // Exit active CPU at the end of my ADC_ISR and it worked!

    As for the arithmetic in the ISR, this is the only function I really need so I am going to keep it in the ISR for now since I will not be adding to the program,


    I appreciate the help!


    Connor Connaughton

**Attention** This is a public forum