maximum frequency for timer triggered ADC

Status
Not open for further replies.

ossi

Well-known member
I have used the timer_adc example code to write the code given below. I want to sample the ADC with high frequency and output its value via pwm. The code works if I use 500kHz as trigger rate. I can see the ADCinterrupt routine working using the "debug-pin" pin5. The code does not work with 1MHz as frequency. I dont see any activity on pin5. If I eliminate the PWM code the ADCsampling seems to work also with 1MHz. What determines the max ADC trigger speed? Why is it influenced by PWM ?


Code:
int LEDpin = 5 ;
int PWMpin = 19 ;

#include <ADC.h>
#include <ADC_util.h>

const int readPin = A0; // ADC0

ADC *adc = new ADC(); // adc object;

void setup() {
  pinMode(LEDpin, OUTPUT);
  pinMode(readPin, INPUT);

  Serial.begin(9600);
  while (!Serial && millis() < 5000) ; // wait up to 5 seconds for serial monitor.
  Serial.println("begin setup");

 boolean withPWM=true ;
  if(withPWM){
    analogWriteRes(10);
    analogWriteFrequency(PWMpin,1000000);
    analogWrite(PWMpin, 512);
    }

  
  ///// ADC0 ////
  adc->adc0->setAveraging(1); // set number of averages
  adc->adc0->setResolution(10); // set bits of resolution
  adc->adc0->setConversionSpeed(ADC_CONVERSION_SPEED::VERY_HIGH_SPEED); // change the conversion speed
  adc->adc0->setSamplingSpeed(ADC_SAMPLING_SPEED::VERY_HIGH_SPEED); // change the sampling speed
  doStart(500000) ;
  Serial.println("End setup");
}

 void doStart(int freq){
  Serial.print("Start Timer with frequency ");
  Serial.print(freq);
  Serial.println(" Hz.");
  adc->adc0->stopTimer();
  adc->adc0->startSingleRead(readPin); // call this to setup everything before the Timer starts, differential is also possible
  adc->adc0->enableInterrupts(adc0_isr);
  adc->adc0->startTimer(freq); //frequency in Hz
  }

volatile uint16_t adc_val ;

void loop() {
   Serial.printf("ADCval=%8d\n",adc_val);
   delay(1000) ;
   }

void adc0_isr() {
  CORE_PIN5_PORTSET = CORE_PIN5_BITMASK; // debug pin=high
  adc_val = (int16_t)ADC1_R0;
  analogWrite(PWMpin, adc_val);
  CORE_PIN5_PORTCLEAR = CORE_PIN5_BITMASK; // debug pin=low
  #if defined(__IMXRT1062__)  // Teensy 4.0
  asm("DSB");
#endif
}
 
Not indicated what Teensy #.# this is working with. Also the version of TeensyDuino in use 1.51 or 1.52 beta# ?

Possible the PWM pin chosen has some shared hardware linkage with ADC sampling? Were other PWMpin = 19 values tried?
 
The crazy thing is: The code is working with 1MHz if I put the PWM initialization behind the doStart() routine.
So the following code is working:
Code:
int LEDpin = 5 ;
int PWMpin = 4 ;

#include <ADC.h>
#include <ADC_util.h>

const int readPin = A0; // ADC0

ADC *adc = new ADC(); // adc object;

void setup() {
  pinMode(LEDpin, OUTPUT);
  pinMode(readPin, INPUT);

  Serial.begin(9600);
  while (!Serial && millis() < 5000) ; // wait up to 5 seconds for serial monitor.
  Serial.println("begin setup");
  ///// ADC0 ////
  adc->adc0->setAveraging(1); // set number of averages
  adc->adc0->setResolution(10); // set bits of resolution
  adc->adc0->setConversionSpeed(ADC_CONVERSION_SPEED::VERY_HIGH_SPEED); // change the conversion speed
  adc->adc0->setSamplingSpeed(ADC_SAMPLING_SPEED::VERY_HIGH_SPEED); // change the sampling speed
  doStart(1000000) ;
  
  analogWriteRes(10);
  analogWriteFrequency(PWMpin,1000000);
  analogWrite(PWMpin, 512);
  
  Serial.println("End setup");
}

 void doStart(int freq){
  Serial.print("Start Timer with frequency ");
  Serial.print(freq);
  Serial.println(" Hz.");
  adc->adc0->stopTimer();
  adc->adc0->startSingleRead(readPin); // call this to setup everything before the Timer starts, differential is also possible
  adc->adc0->enableInterrupts(adc0_isr);
  adc->adc0->startTimer(freq); //frequency in Hz
  }

volatile uint16_t adc_val ;

void loop() {
  // Serial.printf("ADCval=%8d\n",adc_val);
   delay(1000) ;
   }

void adc0_isr() {
  CORE_PIN5_PORTSET = CORE_PIN5_BITMASK; // debug pin=high
  adc_val = (int16_t)ADC1_R0;
  analogWrite(PWMpin, adc_val);
  CORE_PIN5_PORTCLEAR = CORE_PIN5_BITMASK; // debug pin=low
  #if defined(__IMXRT1062__)  // Teensy 4.0
  asm("DSB");
#endif
}
 
While browsing though the source for the timers and ADCs, I think I saw something about the ADC Setup changing some system clock dividers to allow the higher sampling rates. Perhaps changing the clock in the ADC before starting the PWM is workable, but if the PWM is set up first, the ADC timer cannot set a proper divider.. This is all speculation at this point.
 
Different PWM pins are based on different timers - that was the reason to suggest other pins.

This post shows the association for T_4 :: TeensyTimerTool

There may be something more to it - but that seemed like a start ...
 
Status
Not open for further replies.
Back
Top