Variable Delay Pulse

I'm trying to send a ~10µs pulse every MY_DELAY microseconds.

The obvious way to do this would be

void loop(){
  digitalWrite(PIN_NO, HIGH);
  delayMicroseconds(10);
  digitalWrite(PIN_NO, LOW);
  delayMicroseconds(MY_DELAY);
}

However, such an approach is blocking and I can't do much else. Is there anyway I can spawn something to do this asynchronously? Ideally, this would look like:

start_pulse_loop(MY_DELAY) // Start loop sending pulse every MY_DELAY µs
run_something_else() // Blocks for, say, 5 seconds
start_pulse_loop(800) // Updates loop to pulse every 800µs 
// etc...

I'd imagine this is possible with timers, but I'm unfamiliar with them. I'm using an ESP32, if that changes things. Thanks for the help!

Study this discussion.

https://docs.arduino.cc/built-in-examples/digital/BlinkWithoutDelay/

1 Like

have a look at ESP32TimerInterrupt
you could

  1. set output high - start 10uSec timer
  2. 10uSec later on timer interrupt set output low

if you have an oscilloscope put the test in a loop to check it is correct

1 Like

This is th most important information at all.

This is the same timing pattern as for creating RC-servo-pulses.
Which are 1000 to 2000 µsec long pulses once every 20 millisconds.

Your pulss are shorter and occur faster.

I haven't looked into the ESP32-servo library. It might be that simply reducing the timing-constants and adding a set-pulse-pause-time function is sufficient.

THough a RC-Servo-Signal has 50 Hz and you are asking for a signal in the 100 kHz range
best regards Stefan

Add a function to void loop() to do this.

Use delayMicroseconds(10) between the pin changes because 10 micros is so short it's a bump not a block.

But if (MY_DELAY) can be > 10, use a no-block timer for that.

Just FYI, micros() adds 4 every 4 usecs, not add 1 every 1 usec so 10 means 12. You want closest, you stack NOP's, 16 per usec.

Also, use direct port manipulation (write to a PINx register) to flip the pin quicker than Arduino digitalWrite().

1 Like

A hint, compiles, not tested. :neutral_face:

const byte pulsePin = 2;

void setup()
{
  pinMode(pulsePin,OUTPUT);
}
void loop()
{
  static uint32_t
    timer = micros(),
    myDelay = 1000000, // 1 sec
    pulseLen = 12;
    
    if(micros() - timer >= myDelay)
    {
      timer += myDelay;
    }
    digitalWrite(pulsePin,micros() - timer < pulseLen);  
}
1 Like

example code using ESP32 timers every 100uSec generate a 10uSec pulse

// example code using ESP32 every 100uSec generate a 10uSec pulse

// from  https://github.com/khoih-prog/ESP32TimerInterrupt

#define _TIMERINTERRUPT_LOGLEVEL_ 0

#include "ESP32TimerInterrupt.h"

#define PIN_D19 19  // Pin D19 mapped to pin GPIO19 of ESP32 10uSec pulse
#define PIN_D18 18  // Pin D18 mapped to pin GPIO18 of ESP32 100uSec period square wave

// timer0 generates a 10usec pulse on GPIO19
#define TIMER0_INTERVAL_US 8  // alow 2uSec for execution of instructions
ESP32Timer ITimer0(0);
bool IRAM_ATTR TimerHandler0(void* timerNo) {
  digitalWrite(PIN_D19, LOW);  // level LOW
  ITimer0.stopTimer();         // end of 10uSec pulse
  return true;
}

// Timer1 generates 200uSec period square wave
#define TIMER1_INTERVAL_US 100
ESP32Timer ITimer1(1);
bool IRAM_ATTR TimerHandler1(void* timerNo) {
  digitalWrite(PIN_D18, !digitalRead(PIN_D18));  // 100uSec period square wave
  ITimer0.restartTimer();       // start 10uSec pulse
  digitalWrite(PIN_D19, HIGH);  // HIGH
  return true;
}

void setup() {
  pinMode(PIN_D19, OUTPUT);
  pinMode(PIN_D18, OUTPUT);
  digitalWrite(PIN_D19, LOW);
  Serial.begin(115200);
  while (!Serial && millis() < 5000)
    ;
  delay(500);
  Serial.print(F("\nESP32 every 100uSec generate a 10uSec pulse - board "));
  Serial.println(ARDUINO_BOARD);

  // Interval in microsecs
  if (!ITimer0.attachInterruptInterval(TIMER0_INTERVAL_US, TimerHandler0))
    Serial.println(F("Can't set ITimer0. Select another freq. or timer"));
  else
    Serial.println(F("Timer0 started  OK generate a 10uSec pulse "));

  ITimer0.stopTimer();
  // Interval in microsecs
  if (!ITimer1.attachInterruptInterval(TIMER1_INTERVAL_US, TimerHandler1))
    Serial.println(F("Can't set ITimer1. Select another freq. or timer"));
 else
    Serial.println(F("Timer1 started  OK generate a 100uSec period square wave "));
  Serial.flush();
}

void loop() {
}

generates a square wave 200uSec period
image

with a 10uSec pulse
image

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.