teensy 3.6 ADC resolution problem

Status
Not open for further replies.

Abadi alali

Active member
Hello,

I am using the ADC_0 in the teensy 3.6 as follows:

Code:
std::array<volatile uint16_t, 4096> buffer1;
volatile size_t write_pos1 = 0;

\\the setup

void setup() {
  adc.adc0->setAveraging(1);
  adc.adc0->setResolution(12);
  adc.adc0->setConversionSpeed(ADC_CONVERSION_SPEED::HIGH_SPEED);
  adc.adc0->setSamplingSpeed(ADC_SAMPLING_SPEED::HIGH_SPEED);
  adc.adc0->analogRead(adc_pin0); // performs various ADC setup stuff
  adc.setReference(ADC_REFERENCE::REF_3V3, ADC_0);
  adc.enableInterrupts(ADC_0);
}

\\ the read part 

void adc0_isr() {
  if (write_pos1 <= 1025) {
    // Serial.println(write_pos1);
    size_t write_pos_ = write_pos1;
    buffer1[write_pos_] = adc.adc0->readSingle();
    write_pos_++;
    if (write_pos_ >= buffer1.size()) write_pos_ = 0;
    write_pos1 = write_pos_;
  }
  if (write_pos1 == 1026)
  {
    // Serial.println(" Stopping PDB");

    stopPdb();
    noInterrupts();
    write_pos1 = 0;
    write_pos2 = 0;
    reading = false;
    //

  }
}

this is just the initialization part of the code I am using the Pdb and everything works but I am not getting the resolution I expect to get and I get a high error. I have been testing the code with DC voltage and it looks like I have a resolution much less than 12 Bits.

I get this output when I am putting 508 mV DC into pin A9 (my adc input pin)
download.png

is this a normal output or am I doing something wrong?
 
You could try to lower sampling speed eg. to "VERY_LOW_SPEED" and the conversion speed to "VERY_LOW_SPEED".
 
IMNSHFO the problem is not with resolution, but with noise.

The Teensy ADCs are delta-sigma converters which require a lower source impedance, the shorter the sampling interval and the higher the sampling rate is. If the source can not follow up with recharging the internal integrator capacitor after each sampling, you get these noisy readings.

Second, a required 12bit resolution (72dB of signal dynamics) asks for a signal to noise ratio of >78dB. This can’t be obtained in a “dirty” digital environment but with meticulous optimization of the wiring (filtering/shielding). On an open breadboard with a high impedance potentiometer, lousy grounding and shielding, and long wires acting as antennas for digital RF noise, it’s already impossible to get stable 10bit readings.

Don’t blame the ADC for just showing the weakness of your analog circuitry...
 
Yes, depending on the conversion rate that you want you should lower the sampling and the conversion speeds, especially the sampling one as your converted voltage is lower than your input voltage (it's possible that your 3.3V isn't exactly 3.3 V though).
 
If the DC voltage to measure is relatively low as in your example, it might help, too, to switch over to the cleaner internal 1.2V band gap reference for the ADC, always under the condition that external noise sources are eliminated, the input signal is well low-impedance low-pass filtered before fed into the ADC, and the conversion settings have been optimized for the needed bandwidth and the resulting sampling rate.

Actually, you don't even tell at which rate, you did the samples resulting in your picture above...
 
Thank you so much, I have double checked my circuit and after some testing, I was able to clearly see that it is the noise from the circuit that is affecting but I wasn't able to see it at first in the oscilloscope.
 
another thing if I may ask and sorry for that, so I am using the PDB to sample at different frequencies using ADC0 the problem is whenever I go below a threshold the PDB stops working properly in a way that it gets stuck at a specific sampling frequency or something and I can run it back at frequencies below that threshold but never above it ( the threshold seems to be around 600 Hz) so is there any reset I have to trigger or something?
my code for the pdb is as follows:

Code:
// freq set
uint8_t prescaler = 0; // from 0 to 7: factor of 1, 2, 4, 8, 16, 32, 64 or 128
uint8_t mult = 0; // from 0 to 3, factor of 1, 10, 20 or 40

//int f=10000;
void setPdbFreq(uint32_t freq) {

  if (freq > F_BUS) {
    Serial.print("freq is very High");
    return; // too high
  }
  if (freq < 1) {
    Serial.print("freq is very low");
    return; // too low
  }
  uint32_t mod = (F_BUS / freq);

  const uint32_t min_level = 0xFFFF;

  if (mod > min_level) {
    if ( mod < 2 * min_level ) {
      prescaler = 1;
    }
    else if ( mod < 4 * min_level ) {
      prescaler = 2;
    }
    else if ( mod < 8 * min_level ) {
      prescaler = 3;
    }
    else if ( mod < 10 * min_level ) {
      mult = 1;
    }
    else if ( mod < 16 * min_level ) {
      prescaler = 4;
    }
    else if ( mod < 20 * min_level ) {
      mult = 2;
    }
    else if ( mod < 32 * min_level ) {
      prescaler = 5;
    }
    else if ( mod < 40 * min_level ) {
      mult = 3;
    }
    else if ( mod < 64 * min_level ) {
      prescaler = 6;
    }
    else if ( mod < 128 * min_level ) {
      prescaler = 7;
    }
    else if ( mod < 160 * min_level ) { // 16*10
      prescaler = 4;
      mult = 1;
    }
    else if ( mod < 320 * min_level ) { // 16*20
      prescaler = 4;
      mult = 2;
    }
    else if ( mod < 640 * min_level ) { // 16*40
      prescaler = 4;
      mult = 3;
    }
    else if ( mod < 1280 * min_level ) { // 32*40
      prescaler = 5;
      mult = 3;
    }
    else if ( mod < 2560 * min_level ) { // 64*40
      prescaler = 6;
      mult = 3;
    }
    else if ( mod < 5120 * min_level ) { // 128*40
      prescaler = 7;
      mult = 3;
    }
    else { // frequency too low
      Serial.print("freq is very low");
      return;
    }

    mod >>= prescaler;
    if (mult > 0) {
      mod /= 10;
      mod >>= (mult - 1);
    }
  }

  PDB0_MOD = (uint16_t)(mod - 1);
  PDB0_CH0C1 = PDB_CHnC1_TOS_1 | PDB_CHnC1_EN_1; // PDB triggers ADC0 SC1A
  PDB0_CH1C1 = PDB_CHnC1_TOS_1 | PDB_CHnC1_EN_1; // PDB triggers ADC1 SC1A
  PDB0_SC = ADC_PDB_CONFIG | PDB_SC_PRESCALER(prescaler) | PDB_SC_MULT(mult) | PDB_SC_LDOK;
}


void startPdb() {
  PDB0_SC |= PDB_SC_PDBEN | PDB_SC_SWTRIG;
}

void stopPdb() {
  PDB0_SC &= ~PDB_SC_PDBEN;
}

and this is how I start the pdb

Code:
[B]setPdbFreq(freq);
        delay(1000);
        interrupts();
        PDB0_SC = ADC_PDB_CONFIG | PDB_SC_PRESCALER(prescaler) | PDB_SC_MULT(mult) | PDB_SC_LDOK;
        startPdb();
[/B]
 
Status
Not open for further replies.
Back
Top