Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 5 of 5

Thread: Maximizing ADC readout Teensy 4

Hybrid View

  1. #1
    Junior Member
    Join Date
    Nov 2020
    Posts
    9

    Maximizing ADC readout Teensy 4

    I am trying to maximize the ADC performance in my application on a Teensy 4.0. It is not going to be much more complex than the attached code. To test this I'm using another Teensy to send a pulse 50us wide every 2 seconds, I verified with a oscilloscope this is 50.54us wide. I am able to measure ~17 high ADC values with this code, suggesting a 0.34 MHz ADC rate. This seems a little bit slower than I would have expected, but I also cannot find specs on the ADC in the teensy 4.0.

    If there is a way to get >0.5MHz or more out of the ADC I would be pretty happy. My fiddling around suggests the bottle neck is the ADC waiting at the isComplete() step. If I change the while(!isComplete()) to a if/else to count the number of times loop is run between isComplete, it's 18 loops.

    Code:
    #include <ADC.h>
    #include <ADC_util.h>
    #include <CircularBuffer.h>
    
    const int readPin = A9; // ADC0
    
    ADC *adc = new ADC(); // adc object
    
    uint32_t currTime = 0;
    uint32_t sample_count = 0;
    uint16_t val = 0;
    const int nsamples = 2000;
    CircularBuffer<uint16_t, nsamples> wf_buffer;
    CircularBuffer<uint16_t, nsamples> ts_buffer;
    const int pre_sample = 50;
    const int post_sample = (nsamples - pre_sample);
    int trigger = 0; // 0 if not triggered, otherwise samples since trigger
    const int threshold = 500;
    uint32_t num_triggers = 0;
    uint32_t checksum = 0;
    uint32_t uptime;
    
    
    void setup() {
      Serial.begin(250000);
      adc->adc0->setReference(ADC_REFERENCE::REF_3V3);
      adc->adc0->setResolution(12);
      adc->adc0->setConversionSpeed(ADC_CONVERSION_SPEED::VERY_HIGH_SPEED);
      adc->adc0->setSamplingSpeed(ADC_SAMPLING_SPEED::VERY_HIGH_SPEED);
      adc->adc0->startContinuous(readPin);
      Serial.println("Begin...");
    }
    
    void loop() {
      currTime = micros();
      
      while(!adc->adc0->isComplete());
      val = adc->adc0->analogReadContinuous();
      wf_buffer.push(val);
      ts_buffer.push(currTime);
      if ((val > threshold) & (trigger == 0)) {
        trigger += 1;
      }
      else if (trigger == post_sample) {
        // write out the WF to the serial
        sendData();
        // reset trigger
        trigger = 0;
      }
      else if (trigger > 0) {
        // increment trigger until we get to the desired length
        trigger += 1;
      }
    }
    
    void sendData()
    {
      Serial.print("Waveform Start ");
      Serial.println(millis());
      checksum = 0;
      for (int i = 0; i < 1000; i++) {
        checksum += wf_buffer[i];
        Serial.print(ts_buffer[i]);
        Serial.print(",");
        Serial.println(wf_buffer[i]);
      }
      Serial.print("Checksum ");
      Serial.println(checksum);
      Serial.print("Waveform End ");
      Serial.println(millis());
      Serial.println("ZZZ");
      delay(10);
    }

  2. #2
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    15,271
    Adjust the : adc->adc0->setAveraging(0); // set number of averages

    It will sit longer taking multiple readings to average if that is higher - not sure of the default

    >> * \param num can be 0, 4, 8, 16 or 32.

  3. #3
    Junior Member
    Join Date
    Nov 2020
    Posts
    9
    Adding adc->adc0->setAveraging(0); has no effect, I assumed it was the default, but it is now in my code, it is good to be explicit! Thanks

  4. #4
    Senior Member
    Join Date
    May 2015
    Location
    USA
    Posts
    1,084

  5. #5
    Junior Member
    Join Date
    Nov 2020
    Posts
    9
    I wanted to change resolution to see if that was going to effect things. In doing so I se that these lines are needed, although I do not understand them (and expecially the comments)
    Code:
      adc->adc0->enableCompare(1.0/3.3*adc->adc0->getMaxValue(), 0); // measurement will be ready if value < 1.0V
      adc->adc0->enableCompareRange(1.0*adc->adc0->getMaxValue()/3.3, 2.0*adc->adc0->getMaxValue()/3.3, 0, 1); // ready if value lies out of [1.0,2.0] V
    After adding them I see now >1MHz for all resolutions I've tried.

    Even more mysterious, reverting now to my old code version I still get >1MHz. Any idea what happened?

    The current code in full
    Code:
    #include <ADC.h>
    #include <ADC_util.h>
    #include <CircularBuffer.h>
    
    const int readPin = A9; // ADC0
    
    ADC *adc = new ADC(); // adc object
    
    uint32_t currTime = 0;
    uint32_t sample_count = 0;
    uint16_t val = 0;
    const int nsamples = 2000;
    CircularBuffer<uint16_t, nsamples> wf_buffer;
    CircularBuffer<uint16_t, nsamples> ts_buffer;
    const int pre_sample = 50;
    const int post_sample = (nsamples - pre_sample);
    int trigger = 0; // 0 if not triggered, otherwise samples since trigger
    const int threshold = 500;
    uint32_t num_triggers = 0;
    uint32_t checksum = 0;
    uint32_t uptime;
    uint32_t loops = 0;
    
    
    void setup() {
      Serial.begin(250000);
      adc->adc0->setReference(ADC_REFERENCE::REF_3V3);
      adc->adc0->setResolution(12);
      adc->adc0->enableCompare(1.0/3.3*adc->adc0->getMaxValue(), 0); // measurement will be ready if value < 1.0V
      adc->adc0->enableCompareRange(1.0*adc->adc0->getMaxValue()/3.3, 2.0*adc->adc0->getMaxValue()/3.3, 0, 1); // ready if value lies out of [1.0,2.0] V
      adc->adc0->setAveraging(0);
      adc->adc0->setConversionSpeed(ADC_CONVERSION_SPEED::VERY_HIGH_SPEED);
      adc->adc0->setSamplingSpeed(ADC_SAMPLING_SPEED::VERY_HIGH_SPEED);
      adc->adc0->startContinuous(readPin);
      Serial.println("Begin...");
    }
    
    void loop() {
      currTime = micros();
    
      if (adc->adc0->isComplete()) {
        //while(!adc->adc0->isComplete());
        val = adc->adc0->analogReadContinuous();
        wf_buffer.push(val);
        ts_buffer.push(currTime);
        if ((val > threshold) & (trigger == 0)) {
          trigger += 1;
        }
        else if (trigger == post_sample) {
          // write out the WF to the serial
          sendData();
          // reset trigger
          trigger = 0;
        }
        else if (trigger > 0) {
          // increment trigger until we get to the desired length
          trigger += 1;
        }
        loops = 0;
      }
      else {
        loops+=1;
      }
    }
    
    void sendData()
    {
      Serial.print("Waveform Start ");
      Serial.println(millis());
      checksum = 0;
      for (int i = 0; i < 1000; i++) {
        checksum += wf_buffer[i];
        Serial.print(ts_buffer[i]);
        Serial.print(",");
        Serial.println(wf_buffer[i]);
      }
      Serial.print("Checksum ");
      Serial.println(checksum);
      Serial.print("Waveform End ");
      Serial.println(millis());
      Serial.println("ZZZ");
      Serial.print("Loops/conversion=");
      Serial.println(loops);
      delay(10);
    }

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •