Voltage reference question

Status
Not open for further replies.

unicornpower

Well-known member
I'm trying to make use of both ADCs on the Teensy 3.6 using the ADC.h library. One will be dedicated to the audio library, and the other will be used to read the value of potentiometers.

As I mentioned in another post, it does not seem to be possible to set the voltage reference of ADC_1 if ADC_0 is in use by the audio library (it just get's overriden, even if I reset it before each analog read). If someone knows how to do this, please tell me! :)

My potentiometers are currently connected to the 3.3V rail, so with the 1.2V voltage reference set by the audio library, I only get a reading from half a turn of the pot.

My question is, assuming the vref cannot be set independently for each ADC, is there a to get access to the 1.2V vref on the board, so I can connect my pots to it? AREF is at 3.3V regardless it seems. I see on the Teensy schematic there's a VREF_OUT, but I can't see it broken out on the board anywhere.

Obviously I could create my own 1.2V rail, which is what I'll probably end up doing, but I'd like to reduce components as much as possible.

Thanks,
Scott
 
I believe this should be possible, but you may need to access the hardware registers to do it.

The code for analogReference() and analogRead() is in analog.c. As you can see, all the functions have pretty much the same code copied twice for ADC0 and ADC1. If you just copy this code and delete all the stuff for ADC0, maybe you can use it to configure just ADC1 the way you want?

Regarding the 1.2V reference, while you could possibly access it by soldering a wire to one of the very tiny parts, the it's not a strong enough (or technically speaking low enough impedance) to use for the current to pots. You'd need an opamp to buffer the signal.
 
Thanks for the reply, Paul. I'm using the ADC library, and setting the ADC 1 ref voltage with that (see below for simple example). I assumed that would do the same thing as you suggest, e.g setting the hardware registers. It seems the audio library is overriding it somehow? It works fine if I don't use the audio library.

Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <Bounce.h> 
#include <ADC.h>

ADC adc;
AudioInputAnalog audio_input;

// the setup routine runs once when you press reset:
void setup()
{
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);

  adc.setReference( ADC_REFERENCE::REF_1V2, ADC_0 );
  adc.setReference( ADC_REFERENCE::REF_3V3, ADC_1 );
}

// the loop routine runs over and over again forever:
void loop()
{
  adc.setReference( ADC_REFERENCE::REF_3V3, ADC_1 ); // this seems to be ignored if audio enabled
  int sensorValue = adc.analogRead( A16, ADC_1 );
  // print out the value you read:
  Serial.println(sensorValue);
  delay(1);        // delay in between reads for stability
}
 
Think I've fixed it! The issue was this sequence of events.

1. ADC class is constructed, setting its voltage reference to 3.3V for both ADCs
2. Audio library initialises, setting voltage reference to 1.2V for both ADCs
3. My setup code runs, attempts to set ADC_1 to 3.3V, but this function early outs, because it thinks it's already set to that value (ADC_module.cpp line 238 https://github.com/pedvide/ADC/blob/master/ADC_Module.cpp)

To avoid changing the interface to the ADC class (adding a flag to force_set or similar), I simply set the reference twice. Once to 1.2V, to reset the analog_reference_internal member, and then to 3.3V, see code below.

I think ideally, the audio library would be changed to update the ADC states, or the ADC class would provide an interface to force set the reference voltage. Anyway, I'm happy to have found this..

Code now looks like this

Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <Bounce.h> 
#include <ADC.h>

ADC adc;
AudioInputAnalog audio_input;

// the setup routine runs once when you press reset:
void setup()
{
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);

  // Audio library has overriden this, so need to reset the reference voltages
  adc.setReference( ADC_REFERENCE::REF_1V2, ADC_1 ); // NOTE: ADC CODE CHECKS FOR SETTING SAME VALUE, SO SET IT TO SOMETHING ELSE FIRST
  adc.setReference( ADC_REFERENCE::REF_3V3, ADC_1 );
}

// the loop routine runs over and over again forever:
void loop()
{
  int sensorValue = adc.analogRead( A16, ADC_1 );
  sensorValue;
  // print out the value you read:
  Serial.println(sensorValue);
  delay(100);        // delay in between reads for stability
}
 
Actually, what I said above isn't really a fix. It DOES successfully change the voltage reference of ADC_1, and the Teensy doesn't crash, but it seems to screw up the audio library, and no sound is heard, even though the program is still running. Commenting out the lines where I change the reference voltage results in the audio working. I can happily read from ADC_1 (not shown in the code for simplicity), but not change the reference voltage. Presumably some of the ADC_0 registers are also changed (in fact looking at the ADC library code I can see they are). It's unfortunate the ADC library doesn't deal with this. I shall attempt your suggestion, Paul. Will I need to recalibrate ADC_1 after changing the voltage reference, or can I simply set? Thanks!

ADC1_SC2 = ADC_SC2_REFSEL(1); // 1.2V ref?

Code:
#include <Audio.h>
#include <Wire.h>
#include <SD.h>
#include <SPI.h>
#include <SerialFlash.h>
#include <ADC.h>


// wrap in a struct to ensure initialisation order
struct IO
{
  ADC                         adc;
  AudioInputAnalog            audio_input;
  AudioOutputAnalog           audio_output;

  IO() :
    adc(),
    audio_input(A0),
    audio_output()
  {
  }
};

IO io;


AudioConnection       patchCord1(io.audio_input, 0, io.audio_output, 0);

void setup()
{
  Serial.println("Setup BEGIN");
  
  AudioMemory(12);
  
  Serial.begin(9600);

  // THIS WILL CAUSE THE AUDIO LIBRARY TO STOP EMITTING SOUND
  // Audio library has overriden this, so need to reset the reference voltages
  io.adc.setReference( ADC_REFERENCE::REF_1V2, ADC_1 ); // NOTE: ADC CODE CHECKS FOR SETTING SAME VALUE, SO SET IT TO SOMETHING ELSE FIRST
  io.adc.setReference( ADC_REFERENCE::REF_3V3, ADC_1 );
  
  delay(1000);

  Serial.println("Setup END");
}

void loop()
{

}
 
If it's just for MIDI level control (seven bit) or other low-rez, low-frequency control signals then you could just add resistance to the upper leg of your voltage dividers (then re-map for any remaining error).

Unless you need to scan an insane number of pots.
 
Last edited:
If it's just for MIDI level control (seven bit) or other low-rez, low-frequency control signals then you could just add resistance to the upper leg of your voltage dividers (then re-map for any remaining error).

Unless you need to scan an insane number of pots.

Yes, that would work I think. I've had PCBs made, so ideally I'd like to find a software solution, but it's a good backup plan!
 
Has there been any progress with this issue?

It's quite similar to what I wanted to do. I have a couple of inputs I'd like to set to a specific reference voltage (1.8v). But I also have several pots as absolute encoders I'd like to reference at 3.3v.

I was doing to reading trying to figure out the nugget Paul left about the library. I looked at analog.c but I couldn't figure out exactly what he was referencing. But then looked at the Teensy Schematics. If the AREF line is tied to both ADCs, then is there any way to actually reference them to different voltages with just software? Could one ADC on an internal reference and one ADC on an external reference still be possible? Or am I mis-reading the schematic and the entire problem incorrectly. I always reserve the right to be "mistaken".

I'd post code if there was any. It's more of a theoretical problem before I start coding. But in a few sample lessons, I have found pretty much the same thing as unicornpower did in his comments.

Thank you for your time and I love these Teensy's! The improved power is just what most of my projects needed!

Ed
 
Yes, I managed to fix it. See the code here for an example https://github.com/cutlasses/TeensyBoardTestV2/blob/master/TeensyBoardTestV2.ino Basically, the ADC library seems to affect both ADCs on the teensy when you try to set the voltage reference on only one of them. Ideally this will be fixed in the ADC library at some point. In the meantime, I took Paul's advice and cobbled the code below together from looking at analog.c

Code:
void set_adc1_to_3v3()
{

  ADC1_SC3 = 0; // cancel calibration
  ADC1_SC2 = ADC_SC2_REFSEL(0); // vcc/ext ref 3.3v

  ADC1_SC3 = ADC_SC3_CAL;  // begin calibration

  uint16_t sum;

  //serial_print("wait_for_cal\n");

  while( (ADC1_SC3 & ADC_SC3_CAL))
  {
    // wait
  }

  __disable_irq();

    sum = ADC1_CLPS + ADC1_CLP4 + ADC1_CLP3 + ADC1_CLP2 + ADC1_CLP1 + ADC1_CLP0;
    sum = (sum / 2) | 0x8000;
    ADC1_PG = sum;
    sum = ADC1_CLMS + ADC1_CLM4 + ADC1_CLM3 + ADC1_CLM2 + ADC1_CLM1 + ADC1_CLM0;
    sum = (sum / 2) | 0x8000;
    ADC1_MG = sum;

  __enable_irq();
  
}
 
unicornpower,

Thanks for the assist! It worked perfectly first try!

But, I'm seeing what I think are normal characteristics for the AREF input. I'll explain what I am seeing and I'm sure there will be somebody to assist.

I found that as you coded the example you sent me, and as inserted into an test sketch works exactly as you intended. That is using the two internal reference voltages of 1.2v and 3.3v.

When EXTERNAL configured and an external 1.8 voltage is applied to AREF. Things go south from there. So I tried some combinations and DVM measurements. Here's what I found and what I suspect. Much of this is probably already common knowledge to most of you.

1. As long as there is no external voltage applied to AREF there is always 3.3v present at AREF.
2. Selecting 3.3 essentially uses the 3.3v volts present at AREF.

This leads me to this:

If there is any external voltage applied to AREF and either of the ADCs are configured for 3.3 volts the external voltage becomes the reference for both. This leads me back to the original comments I made about how AREF is wired making an EXT and 3V3 combination "undoable". I don't like saying "impossible".

Is this correct? Or am I missing something important?

I could use what does work and run the pots at the same external 1.8v reference as the AD8302 but that's not really a lot of voltage to work with. Noise and resolution are my major concern.

Thanks again for the help! It's greatly appreciated!

Ed
 
Thanks, @unicornpower!
This work-around is beauteous and effective (though I wouldn't want to figure out how it works).
Have you made a request to @pedvide to change the ADC side to make this unnecessary?
 
Shock is about the only downside Im aware of. Higher voltage is more efficient.

12V is a legacy of ancient tech.


Sent from my iPhone using Tapatalk
 
Status
Not open for further replies.
Back
Top