LM324 op-amp output to Teensy 3.2 analog input reads 0.00. Meter shows 2.96v. Help?

Status
Not open for further replies.

MisterBill

New member
Hello. I just started using Teensy a few days ago to allow me to use the FreqMeasure library to check the clock frequency of a processor on a board under test. The main brain in the fixture is an Arduino Mega 2560 v3, but a) I'm already using every single pin it has, and b) it's not fast enough to measure the frequency (16Khz or 32Khz, depending on the mode) and still get everything else done. I got FreqMeasure and I2C communication between the Mega and the Teensy working pretty easily. But then I realized I needed to measure a 3.3V and -3.3V supply, and thought, "Hey - I can just use the analog inputs on the Teensy and request the values via I2C like I'm doing with the frequency!". But for some reason, while the 3.3v reads fine on A7, I'm getting 0.00 on A8, which is connected to the output of a unity gain inverting LM324 that gives me 2.96V on a meter when fed -2.96V. I've tried swapping pins around, inserting delays, etc, but nothing works. Any suggestions? I realize I need to add some code to reply to requests for the voltage, etc, but I need to *get* it first! Any help would be appreciated. Impendance issue, maybe?

-Bill

Code:
#include <Wire.h>
#include <FreqMeasure.h>


byte SlaveReceived = 0;
int frequency;
double sum = 0;
int count = 0;
int maxWait = 10000; //max # of ms to wait for a reading before returning 0

float v33; //+3.3v from CBA
float n33; //-3.3v from CBA

void setup() {
  //Serial.begin(57600);
  Wire.begin(8);
  FreqMeasure.begin();
  //Wire.onReceive(receiveEvent);           //Function call when Slave receives value from master
  Wire.onRequest(requestEvent);           //Function call when Master request value from Slave

}

void loop() {
 
  v33 =(analogRead(A8) / 1023 * 3.3);
  //delay(500);
  n33 = (analogRead(A9) / 1023 * 3.3); //-3.3v inverted via LM324 to +3.3v
  //delay(500);
  Serial.println("v33=" + String(v33));
  Serial.println("n33=" + String(n33));

  if (FreqMeasure.available()) {
    // average several readings together
    sum = sum + FreqMeasure.read();
    count = count + 1;
    if (count > 30) {
      frequency = FreqMeasure.countToFrequency(sum / count);
      Serial.println("[" + String(frequency) + "]");
      sum = 0;
      count = 0;
    }
  }
}

void requestEvent(void)                                //called when master wants value from slave
{
  //  int start = millis();
  //  frequency = 0;
  //  do {
  //
  //  }
  //} while ((frequency == 0) && (millis() < (start + maxWait)));
  byte msb = highByte(frequency);
  byte lsb = lowByte(frequency);
  //  Serial.print("[" + String(frequency) + "]");
  //  Serial.println("Sending: " + String(msb) + " " + String(lsb));
  Wire.write(msb);                          // sends one byte
  Wire.write(lsb);

}
Capture.PNG
 
> v33 =(analogRead(A8) / 1023 * 3.3);

I don't know why there is a difference between pins, but add a decimal to 1023 to make it use floating point.
 
> v33 =(analogRead(A8) / 1023 * 3.3);

I don't know why there is a difference between pins, but add a decimal to 1023 to make it use floating point.

If you write that as: v33 =(analogRead(A8) * (3.3 / 1023.0));

You get the same result but let the compiler combine the constants saving a floating point op at run time.

I would be very careful with that inverter circuit. The common mode input voltage is outside the specified range of the LM324. (The inverting input will be at -Vout/gain.) The input range of some opamps does go slightly below their lower voltage rail but the LM324 is not one of them. Or at least not in the data sheet I looked at.
 
> saving a floating point op at run time

You can also leave the expression in the same order and specify the gcc option "-ffast-math".
 
Did I miss something (using a TI data sheet)? I don't see a problem with the LM324 - even if Vin exceeds the expected -3.3V to 0V range (except for over voltage to the ADC input).
 
the lm324 has restricted input voltage common mode range - 1.7 v from +supply and
0v from -supply so if it is powered from 5v the inputs can go as high as 3.3 with no
tolerance and no margin. the output swing is also limited. with 5v supply output swing
high is 3.5 typ 3.3 min and output swing low is 5 mv typ 20 mv min even with a 10k rl
from out to gnd. also, if the input common mode voltage range is exceeded (depending
on where the other input is) the output can lock high (ie 1.5-1.7 volt from +supply) -
this is sometimes referred to as phase inversion.

all in all not the best choice to drive a teensy adc input - much better to use a cmos
rail to rail in and rail to rail out amplifier in a non-inverting gain of 1 in this application.
for example the TLV2370 available from Digikey. there are dozens and dozens of
amplifiers like this available.
 
I am reminded of an old DATAQ DI-194 data acquisition system I have. It used an ADC with a 0-5V input range but had a resistor input network that let it measure -10 to +10V.
 
had overlooked on the schematic -non inverting input of lm324 at ground - will not work as desired that way.
non inverting input would have to be at 1.65 or so volts for proper action.

edit - is that a minus sign on the 3.3 v input to the amp? if so a gnd connection for the non inverting input
would be ok -3.3 in would be 3.3 out but -3.4 in would be 3.4 out and that is beyond the worst case spec
for the 324 so maybe you would want to decrease the feedback resistor a little to give yourself some margin
and calculate that out after you make the measurement.
 
Last edited:
You don't really need an opamp.

If you don't need perfect accuracy, connect 2 resistors in series between the +3.3 V and -3.3 V line that you want to measure. Connect the junction to the ADC input. Make the R to the +3.3 V slightly lower in resistance than the other one -- say 10k to +3.3 V (call it R1), and the other one 15k (call it R2). Now the voltage at the junction is:
Vmid = (VHIGH*15k+VLOW*10k)/25k. Measure VHIGH first (as you are doing -- but if the +3.3 V is above the Teensy's '3.3V', the ADC will saturate at 1023), and then measure VMID and calculate the VLOW value.

Your largest error will be the resistors tolerance -- maybe you can get to within a few %, or calibrate it if you need more accuracy. You would have nearly the same error in the opamp anyway -- its gain of '-1' depends on 2 resistors too.
 
Status
Not open for further replies.
Back
Top