How to select a timer in ESP32 Arduino API 3.0

Thanks to several real knowledgeable members I'm starting to understand the nuances of esp32 timers. I still has a few question to resolve: In API version 2.0 you selected which 1 of the 4 timers you wanted in "timerBegin(timer#, pre-scaler,count_direction)" now there is only 1 parameter "Frequency". Where do I select the timer number? A second question is what are the allowable frequencies? The pre-scaler parameter was straight forward as the register is 16 bits.

See the timer section in

I am either overlooking something in that document or timer selection is missing.

Try here

Thanks to member ec2021 I found this website: [https://wolles-elektronikkiste.de/en/interrupts-part-3-timer-interrupts] There is a good write-up on using timers with api version 3 The frequency must not be higher than 40 MHz and not lower than 1250 Hertz

an ESP32 has 4 timers - you check the return from timerBegin() - if it is NULL it failed
this uses 4 timers to generate three phase square waves

// ESP32 three phase square wave variable duty cycle using timers

#define phase1 16  // signal output pins
#define phase2 18
#define phase3 17

unsigned long int period = 10000;                       // timer interval in uSec
unsigned long duty_cycle = 50;                          // percentage
unsigned long pulse_width = period * duty_cycle / 100;  // * 50 / 100;

hw_timer_t *timerperiod = NULL;  // hardware timer
hw_timer_t *timerPhase1 = NULL;  // hardware timer
hw_timer_t *timerPhase2 = NULL;  // hardware timer
hw_timer_t *timerPhase3 = NULL;  // hardware timer

// interrupt service routine to generate HIGH levels
volatile int counter = 0;  // interrupt counter
void ARDUINO_ISR_ATTR onTimer() {
  static byte state = 0;  // determines which phase to generate
  switch (state) {
    case 0:
      digitalWrite(phase1, HIGH);                      // set phase output HIGH
      timerWrite(timerPhase1, 0);                      // clear timer
      timerAlarm(timerPhase1, pulse_width, false, 0);  // generate one shot
      break;
    case 1:
      digitalWrite(phase2, HIGH);
      timerWrite(timerPhase2, 0);
      timerAlarm(timerPhase2, pulse_width, false, 0);  // generate one shot
      break;
    case 2:
      digitalWrite(phase3, HIGH);
      timerWrite(timerPhase3, 0);
      timerAlarm(timerPhase3, pulse_width, false, 0);  // generate one shot
      break;
  }
  if (++state >= 3) state = 0;  // reset state ?
  counter++;
}

// interrupt service routines to generate LOW levels
void ARDUINO_ISR_ATTR onTimerPhase1() {
  digitalWrite(phase1, LOW);  // set phase output LOW
}

void ARDUINO_ISR_ATTR onTimerPhase2() {
  digitalWrite(phase2, LOW);
}

void ARDUINO_ISR_ATTR onTimerPhase3() {
  digitalWrite(phase3, LOW);
}

void setup() {
  Serial.begin(115200);
  delay(2000);
  Serial.println("\n\nESP32 timer three phase square wave with duty Cycle");
  pinMode(phase1, OUTPUT);  // enable phase outputs
  pinMode(phase2, OUTPUT);
  pinMode(phase3, OUTPUT);
  digitalWrite(phase3, 1);
  // setup timer interrupts for 1KHz three phase
  if ((timerperiod = timerBegin(10000000)) == NULL)  // Set timer frequency to 10Mhz
    Serial.println("ERROR! timer period initialisation failed");
  else Serial.println("Timer period initialization OK");
  if ((timerPhase1 = timerBegin(10000000)) == NULL)  // Set timer frequency to 10Mhz
    Serial.println("ERROR! timer Phase 1 initialisation failed");
  else Serial.println("Timer Phase 1 initialization OK");
  if ((timerPhase2 = timerBegin(10000000)) == NULL)  // Set timer frequency to 10Mhz
    Serial.println("ERROR! timer Phase 2 initialisation failed");
  else Serial.println("Timer Phase 2 initialization OK");
  if ((timerPhase3 = timerBegin(10000000)) == NULL)  // Set timer frequency to 10Mhz
    Serial.println("ERROR! timer Phase 3 initialisation failed");
  else Serial.println("Timer Phase 3 initialization OK");
  timerAttachInterrupt(timerperiod, &onTimer);        // Attach timer ISR for period timing
  timerAttachInterrupt(timerPhase1, &onTimerPhase1);  // attch timers ISR for pulse timing
  timerAttachInterrupt(timerPhase2, &onTimerPhase2);
  timerAttachInterrupt(timerPhase3, &onTimerPhase3);
  // Set alarm to call onTimer function every second (value in 10 microseconds).
  // Repeat the alarm (third parameter) with unlimited count = 0 (fourth parameter).
  timerAlarm(timerperiod, period / 3, true, 0);
  Serial.println("period increment > (* by 10) decrement < (/ by 10)");
  Serial.println(" duty cycle enter 1 (for 10%) to 9 (for 90%)\n");
}

// display interrupt coun ter every seconds
void loop() {
  static unsigned long int unit = 10000;
  // check if updated period or duty cycle entered
  while (Serial.available()) {  // if characters entered read them
    char ch = Serial.read();
    if (!isprint(ch)) continue;
    if (ch == '>') {
      period += unit;
      if (period / unit >= 10) unit *= 10;
    }
    // < decrement value by 1 unit  - minimum is 1 ?
    if (ch == '<' && period != 1) {
      if (period == unit) unit = unit / 10;
      period -= unit;
    }
    // * increment value by 10 ?
    if (ch == '*') {
      period = unit = unit * 10;
    }
    // / decrement value by 10 - minimum is 1
    if (ch == '/' && period != 1) {
      if (period == unit) unit = unit / 10;
      period = unit;
    }
    if ((ch >= '1') && (ch <= '9')) duty_cycle = (ch - '0') * 10;  // set duty cycle
                                                                   // duty_cycle=50;
    pulse_width = period * duty_cycle / 100;
    Serial.print("period = ");
    Serial.print(period);
    Serial.print(" frequency = ");
    Serial.print(10000000.0 / (period));
    Serial.print(" dutyCycle ");
    Serial.print(duty_cycle);
    Serial.print(" pulse width ");
    Serial.println(pulse_width);
    timerAlarm(timerperiod, period / 3, true, 0);
  }


  // every second print interupt counter
  static unsigned long timert = millis();
  if (millis() - timert >= 1000) {
    Serial.println(counter);
    counter = 0;
    timert = millis();
  }
}

output


probably more efficient to use the Remote Control Transceiver (RMT)
however, if generating multiple signals the the ESP32 does not support the sync manager - use an ESP32S3?