LM4040 external reference with Teensy 3.2

Status
Not open for further replies.

Ross Fish

Member
Hello All!,

My apologies for this being my first post as I'm not very active on internet forums...I'm the guy who actually solders your Teensy 3.2's and have worked closely with Paul on some projects (monolith!) so please DON'T BE A GRUMPY CURMUDGEON.

I'm working on a project right now that requires 20 pots connected to all of Teensy 3.2's ADCs. This particular circuit is susceptible to high noise due to the fact that the variety of users who will use this product will be using a garbage 9v switching power supply that is usually used with guitar effects pedals.

To compensate for this noise, I'm using an LM2940 LDO to generate my 5v supply rail which will be responsible for powering the Teensy. I would like to use that 5v rail into an LM4040 to generate an external 3v reference for the AREF pin.

My reason for needing a precision reference with a pot is because I'm using a switch case statement on a pot that is supposed to have 98 discreet values across it's range. This function of this pot is to select wave tables on a synthesizer, so no glitching! I'm aware I can do both hardware and software filtering (which I will be doing) but ensuring what is coming off the wall is clean is a primary concern of mine, especially across a production run of 50 units.

Proposed circuit:
9v wall wart => LM2940 => LM4040 => Buffer => AREF + Pots
all ICs riddled with bypass caps at power inlets and outlets :)

My questions are as follows:

1.) I have read that ratio metric sensors such as potentiometers (which I'm using) should be powered directly from the 3v3 pin on Teensy 3.2 rather than an external reference. My first prototype did exactly this, but because the original power supply for my application was so shitty (7805) I was getting very noisy pots (almost 0.6vpp!). Should I just use the LDO and the onboard 3v3 regulator instead of using the AREF pin with an LM4040?

2.) In the event that I should use the external reference rather than the onboard 3v3 regulator, I am trying to calculate the value for Rs from the LM4040 datasheet (pg. 1). I am receiving conflicting information from multiple posts on the forum in regards to the AREF pin. I have read that there is a 470ohm series resistor on the AREF pin on Teensy 3.2 meant to be used with an external shunt regulator and am a bit confused as to how that application would match what I'm working with. Isn't it true that Rs would still need to exist to make sure the LM4040 has a load on it? Is the 470ohm series resistor going to mess with the correct value of Rs? I'm not an EE, I'm from an art school background and these types of things usually trip me up. If what I'm reading is correct, would I simply connect the 5v (supply) and 3v (reference) nodes from the LM4040 to the AREF pin with no Rs and then just use the output of that node to connect to my pots?:

LM4040 datasheet (page 1 for reference)
http://www.ti.com/lit/ds/symlink/lm4040-n.pdf

Thank you all and sorry for the long winded post. If I had the capability to send screenshots of my schematic I would. Please let me know if you would like me to clarify anything.

Best,
Ross Fish
Chief Dork
Moffenzeef Modular
 
Ross- the Vref pin of the MCU is connected to the VDDA pin on the Teensy board itself. The VDDA pin is connected to the onboard 3.3V regulator output thru an inductor (ferrite bead). So, unless you removed that (tiny) 470 ohm resistor, you can't feed in an external reference like the LM4040.
My suggestion would be to take the regulated/filtered 3.3V available at the Vref teensy pin, feed it to an op amp in a unity gain buffer configuration, and then feed the pots from that. You'd need to use an op amp that could handle the load current presented by your pot(s), but if you are only using one or two pots (1K or greater) most any op amp would handle this current. Then you are operating the ADC in the ratio-metric mode, since the ADC and pots share the same power source. This is the best way to read pots, in terms of accuracy/linearity.
 
Thanks for the fast response! My initial design did that, it took the onboard 3v3 and fed it into a TL072 unity gain buffer being powered from the same 5v rail as the Teensy and I had lots of noise issues. Thank you for letting me know about the AREF pin, that helped clear it up for me.

I'm using 20, 100k pots from the same buffered output of the TL072. Is there another op amp you would recommend or is a general purpose fine?

I'm going to try swapping out the 7805 for the LDO first and see if it helps.
 
The underlying issue, fluctuations in voltage divider readings, comes up all the time in MIDI projects.

The frequency of the noise is relatively high compared with the human time scale of pot-twiddling. For that reason I'm in the software-filtering camp for getting rid of it in most circumstances (nice tip about an active supply from Ben though.. may look into that).

I can always get at least seven bits of resolution (albeit usually with USB power supply) so 98 positions doesn't sound too daunting. Do you have evidence that you need to clean the power supply further?

I would think the problem would be users with steady enough hands to find the wave they're looking for.
 
I would recommend you stick to 3v3 instead of using an external reference; normally, the ripple should affect both the ADC inputs and VREF at the same time, cancelling each other nicely (in theory!)
With a few tricks you can pull this off almost entirely in software:
-The ADC library allows you to lower the sampling time, this is useful for anything more than 10k pots
-Use a simple filtering scheme such as
Code:
value = (value * 0.9f) + (analogRead(A0) * 0.1f);
-This one is a bit more tricky: implement a form of hysteresis so that it's not possible for the pot value to stay too close to a boundary. This can be achieved by adding/substracting a small offset whenever a transition is detected
-On the hardware side, the usual stuff: keep wires a short as possible, twist them tightly, and use a small capacitor at each input (0.1uf is a good start)

Marc
 
My reason for needing a precision reference with a pot is because I'm using a switch case statement on a pot that is supposed to have 98 discreet values across it's range.

One idea might be to consider using rotary encoders instead of pots.
With encoders, you can have as many discreet positions as you like.
Encoders with detents also can give hepatic feedback so you can feel how many discreet steps you've passed through.
One problem may be that most encoders are incremental and not absolute, so the knob position is relative.
 
I'm using 20, 100k pots from the same buffered output of the TL072.

I'm not getting a clear picture of how you've wired things. Is the opamp powering the pots? Or are the pots getting power from the 3.3V line and their center pins are connected to the opamps as unity gain buffers? Or some other way? A diagram would really help....

Is there another op amp you would recommend or is a general purpose fine?

If the opamp is driving Teensy'd ADC pins, I'd recommend using a 1K resistor between each opamp output and the Teensy pin, and a 10 nF capacitor between each Teensy analog input pin and AGND. Keep the opamp feedback as-is, so these new parts are not in the feedback loop. In other words, for unity gain buffers, keep the opamp's output connected directly to the minus input.

Like most microcontrollers, the analog input pins sample your signal by momentarily shorting it to a small capacitor inside the chip. This sampling action can play havoc with some opamps. First, most opamps have less phase margin for feedback loop stability with driving a capacitive load. Second, they have limited bandwidth, so a sudden (wide bandwidth) change in load current can cause the output to vary quite a lot. It can add up to quite a perfect storm for causing an opamp to momentarily go unstable.

A 1K resistor will greatly lessen the load seen by the opamp when the ADC samples. It also lets you add that 10 nF capacitor directly at the Teensy pin, which greatly improves the charging of the tiny on-chip capacitor. Almost all opamps will go unstable if you put a 10 nF cap right on their output, but having the 1K resistor makes it ok for all but the most troublesome opamps.

If you're adding a mux chip to get lots of inputs, this capacitor needs to be on the signal input side of the mux. Adding a capacitor on the switched side of the mux causes all sorts of speed problems with switching between channels.

If you're using the opamp to try to create a "clean" power source for the pots, well, I'd scrap that idea. Just use the 3.3V power directly. Or if you're really worried about noise, maybe add an inductor (with very low DC resistance) and capacitor to low-pass filter the power. But don't use an opamp to send power to lots of pots. That's just asking for all sorts of trouble with wide bandwidth noise pickup messing up the opamp's output.
 
As for favorite opamps, I personally reach first for a LMV358A whenever I do this sort of general purpose opamp stuff. But like all bipolar input opamps, you do need to be wary of the bias current when using high impedance sources. Usually just adding a resistor in series with the negative input is enough to take care of any DC error from the bias current.

But all opamps with feedback loops are an unstable oscillation liability just waiting to strike. Any sort of capacitive load, or sharp edge signals at their inputs, or wide bandwidth coupling can be trouble, not matter which part you choose. I always try to minimize those sorts of problems with any design using opamps.
 
Interesting info Paul I'd like to understand this better (especially the capacitive-load stability issue)... but I think they were talking about a buffer to keep 3.3 volt supply on the voltage dividers steady.

Could one make the pot supply from an active RC filter with a very low cutoff -- if you wanted dozens of lower-resistance pots perhaps or were otherwise beyond Teensy's regulator limits?

(Which I guess would be no use unless you have an external power source.)
 
General purpose opamps don't make for very good power supplies, especially where the power will be transmitted over lengthy wires. If you look at audio power amp designs, there's almost always an RF load (like a 10 ohm resistor and 0.1 uF poly capacitor) on the output, sometimes even a series inductor + resistor.

Sure, there are lots of ways to improve opamp buffers for powering stuff. But especially for pots which are a ratiometric measurement, I'd avoid using a pot this way.
 
I dug this out of a project that uses a single pot for menu navigation. Since this is on a Teensy LC there's no separate AGND, and the hot side of the 20k pot is connected to 3v3.
It's pretty immune from supply noises, no cap needed in my use case. If I needed more that a few pots I would turn this into a class.

Code:
// Comment this out if you want to use the built-in analogRead() functions
#define USE_ADC


#ifdef USE_ADC
#include <ADC.h>
#endif


const int ANALOG_PIN = A0;            // pot pin
const int STEPS = 98;                 // Number of discreet steps (range is 0 to STEPS - 1)
const unsigned long HOLDOFF = 500;    // Time in msec before accepting preview value as new value
const float FILTER = 0.35f;            // Low pass filter coefficient; smaller value = more sluggish, 1.0f = instant
//   note that this value has been selected for a 50Hz (20ms) loop rate,
//   and should be adjusted to tase

// Working variables
float oldValueCoeff;
float newValueCoeff;
float rawValue;
float innerValue;
unsigned long lastChange = 0;

// Actual selected values
int preview;
int value;

// Loop cycle
const unsigned long CYCLE_TIME = 20;  // 50Hz
unsigned long lastCycle;

#ifdef USE_ADC
ADC *adc = new ADC();                 // adc object;
#endif

inline int readPot(uint8_t pin) {

#ifdef USE_ADC
  return adc->analogRead(pin);
#else
  return analogRead(pin);
#endif
}

void setup() {

  Serial.begin(115200);

  // Initialize adc
#ifdef USE_ADC
  adc->setAveraging(16); // set number of averages
  adc->setResolution(12); // set bits of resolution
  adc->setConversionSpeed(ADC_CONVERSION_SPEED::MED_SPEED); // change the conversion speed
  adc->setSamplingSpeed(ADC_SAMPLING_SPEED::VERY_LOW_SPEED); // change the sampling speed
#else
  analogReadAveraging(16);
  analogReadRes(12);
#endif

  // Pre-compute coefficients
  float stepsPerTicks = (float)STEPS / 4095.0f;
  oldValueCoeff = 1.0f - FILTER;
  newValueCoeff = FILTER * stepsPerTicks;


  // Wait for caps to charge
  delay(200);

  unsigned long now = millis();

  // Initialize filter with first sample
  rawValue = readPot(ANALOG_PIN) * stepsPerTicks;
  innerValue = rawValue;

  preview = floor(rawValue);
  value = preview;

  lastCycle = now;
  lastChange = now;
}

void loop() {

  unsigned long now = millis();

  // Wait for next cycle
  if ((now - lastCycle) < CYCLE_TIME) return;
  lastCycle = now;

  // Compute low pass filtered pot position, all in one step:
  rawValue = (rawValue * oldValueCoeff) + (readPot(ANALOG_PIN) * newValueCoeff);

  //Serial.print(rawValue);
  //Serial.print("\t");
  //Serial.print(value);
  //Serial.println();

  // Check if value is changing
  if (abs(innerValue - rawValue) > 1.0f) {

    // Snap to rawValue to prevent glitches
    innerValue = rawValue;

    // Compute preview by truncating inner value
    preview = floor(innerValue);

    // This is where you would call a "thePotIsMoving" handler
    // to update a display, for instance
    Serial.print("Pot is moving: ");
    Serial.println(preview);

    lastChange = now;
  }

  // If value has not changed for more than the set holdoff, update actual value
  if ((now - lastChange) > HOLDOFF && value != preview) {

    // confirm preview as actual value
    value = preview;

    // This would be where you would call an "onChange" handler
    // that selects something.
    Serial.print("The selected value is ");
    Serial.println(value);
  }

}
 
Hey everyone sorry for the late reply.

Teensy onboard 3v3 reference ==> unity gain buffer (LM358) powered by same Vcc as Teensy (5v from LDO output) ==> each individual attenuator ==> each ADC input

So basically, it's a single buffered 3v3 source being split between all 20 pots. My original design was using just the 3v3 right off of the Teensy with no buffer, and was lower performance than the newest iteration.

The external ref pin is no longer connected to anything.

I wound up getting a cleaner overall power supply for the circuit from the LDO and realized that almost all of the issues I was facing were from using those horrible cheap 9v 1 spot power supplies. The good news is, the LDO + the digital filtering Paul showed me (from the monolith project) are close enough for getting the results that I want and significantly improved since the last revision. The bad news is, the actually ADC measurements still have about 10 bits of noise when the pot is around the 12 o clock position and definitely are not perfect by any means. The noise is sufficiently lower at each end of the pot. This isn't a problem for this project anymore, but I'm curious about getting to the root of the issue so I don't have this problem again.

Paul - that's very good to know about the loading on the ADC inputs. I didn't know that. I'll play around with that and see how it goes.
 
Status
Not open for further replies.
Back
Top