Exact 5MHz pulse using Teensy 4.1

nav

Member
Hello,

i am new to Arduino programming. I am trying to generate multiple PWM pulses (Synchronous) with 50% duty cycle (as close to square wave as possible) using the digitalWriteFast command in Teensy 4.1. I am able to get 4.96MHz as well 5.13MHz but not able to get exact 5.00MHz. Can you guide me through this issue? Also, if I use delayNanoseconds of 100, it is giving me around 4.1 MHz and not 5MHz. Can someone explain the reason behind this as well? I needed exact 5MHz so that I can operate the piezo crystal at its resonance frequency to generate optimum amplitude.
Thank you.
 
Code:
void setup() {
  analogWriteFrequency(2, 5000000);
  analogWrite(2, 128);
}

void loop() {
}

file.png
 
Also, if I use delayNanoseconds of 100, it is giving me around 4.1 MHz and not 5MHz. Can someone explain the reason behind this as well?


In general using a delay style function will be inaccurate as it only accounts for time in the delay call,
not time outside it. If there were a nanos() call (which could be useful for the T4 ...) you could theoretically
fix this like this:

Code:
void loop()
{
  static uint32_t timestamp = 0 ;
  static int state = LOW ;
  if (nanos() - timestamp >= 100)
  {
    timestamp += 100 ;   // update the scheduled time
    digitalWriteFast (pin, state) ;
    state = ! state ;
  }
}
This pattern can be used with millis() or micros() to provide precise timing (modulo any jitter due to interrupts and
the overhead of running the loop).

However here the period is very short and a hardware driven method will be superior.
 
Thank you for your quick reply.
I tried a similar code but this time, frequency is not a problem, synchronization is. I wanted it to be in perfect synchronization from the first to the last wave in a pulse.
My code looks like

void setup() {
analogWriteFrequency(SigA, freq);
analogWriteFrequency(SigB, freq);
pulseON= 100;
pulseOFF= pulseON;
}

void loop() {
for( ; ; ){
analogWrite(SigA, 128);
analogWrite(SigB, 128);
delayMicroseconds(pulseON); //pulseoff for 100 microseconds
analogWrite(SigA, 0);
analogWrite(SigB, 255);
delayMicroseconds(pulseOFF);}

}

I even tried using interrupts to synchronize signals, but no success.

111.png
 
In general using a delay style function will be inaccurate as it only accounts for time in the delay call,
not time outside it. If there were a nanos() call (which could be useful for the T4 ...) you could theoretically
fix this like this:

Code:
void loop()
{
  static uint32_t timestamp = 0 ;
  static int state = LOW ;
  if (nanos() - timestamp >= 100)
  {
    timestamp += 100 ;   // update the scheduled time
    digitalWriteFast (pin, state) ;
    state = ! state ;
  }
}
This pattern can be used with millis() or micros() to provide precise timing (modulo any jitter due to interrupts and
the overhead of running the loop).

However here the period is very short and a hardware driven method will be superior.


Thank you.
I will try this one as well.
 
Thank you.
I will try this one as well.

There is a sample delayNanos() here - claims minimum 50 ns to be expected. :: Teensy-4-0-Bitbang-FAST

Haven't tried it.

Did do something using CYCCNT that is 1/600MHz and it was min ~20 cycles (12 ns?) and then each 1 cycle more update after seemed to add 4 cycles (2.4 ns ) for resolution.

Won't be near the PWM hardware - and PWM is set and forget ...
 
I tried this code and for some reason, I get a fixed time delay which may be time taken by the code to run. I am getting 2.23MHz of frequency. I have attached my code here. Maybe someone can point out what I am doing wrong. I referred to this for nanos() function: https://forum.pjrc.com/threads/60493-A-Higher-Resolution-Micros()-For-The-T4-0?p=236106&viewfull=1#post236106 .

The reason why I am doing this is: "I am supposed to generate two very synchronous pulses of 5MHz that I will use to trigger a medical-grade Ultrasound sensor whose natural frequency is about 5MHz. As I am using only one Ultrasound sensor, I need a burst of these pulses meaning I wanted pulseA and pulseB ON for a few peaks(usually 1 to 2) while pulseA should be HIGH and pulseB should be LOW for the next 1 microsecond."


If possible, can anyone explain why "(highValue | newCycles)" is used in return command of the nanos() function here?


I am sorry if I am asking very simple questions but this is my first time working on microcontrollers and trying to understand them through this forum.

Code:
const int SigA=4, SigB=33;
const int SigC=8, SigD=25;
const int enab1= 6, enab2= 9;
int j=1, i=1;


uint64_t nanos()
{
    static uint32_t oldCycles = ARM_DWT_CYCCNT;
    static uint64_t highValue = 0;

    uint32_t newCycles = ARM_DWT_CYCCNT;
              if (oldCycles < newCycles)
              {
              highValue += 0x0000'0001'0000'0000;
              oldCycles = newCycles;
              }
    return (highValue | newCycles)*(1E9/F_CPU);
}

void setup() {
  pinMode(SigA , OUTPUT);
  pinMode(SigB , OUTPUT);
  pinMode(SigC , OUTPUT);
  pinMode(SigD , OUTPUT);
  pinMode(enab1 , OUTPUT);
  pinMode(enab2 , OUTPUT);
  digitalWrite(enab1, HIGH);
  digitalWrite(enab2, HIGH);
}

void loop() {
    static uint32_t timestamp = 0 ;
    static int state = LOW ;
    
    
    while(i==1){
      unsigned long timenano= nanos();
        if(j==3){
          j+= 1;
          i=2;
        }
        else if(timenano - timestamp >= 100)
          {
          timestamp = timenano ;   // update the scheduled time
          digitalWriteFast(SigA , state);
          digitalWriteFast(SigB , state);
          digitalWriteFast(SigC , state);
          digitalWriteFast(SigD , state);  
          state = ! state ;
          j+= 1;
          }        
        }    
  digitalWriteFast(SigA , LOW);
  digitalWriteFast(SigB , HIGH);
  digitalWriteFast(SigC , LOW);
  digitalWriteFast(SigD , HIGH);
  delayMicroseconds(40);
  j=1;
  i=1;
  
}
 
Last edited:
There is a sample delayNanos() here - claims minimum 50 ns to be expected. :: Teensy-4-0-Bitbang-FAST

Haven't tried it.

Did do something using CYCCNT that is 1/600MHz and it was min ~20 cycles (12 ns?) and then each 1 cycle more update after seemed to add 4 cycles (2.4 ns ) for resolution.

Won't be near the PWM hardware - and PWM is set and forget ...

Thanks for the suggestion.
This worked really fine.
 
Back
Top