FspTimer timer: Varying the frequency of an existing timer

Dear all, I need an accurate periodic timer whose frequency I can change while the program is running.
I have an Arduino R4 WiFi.
Phil Schatzmann's excellent article (bless him) shows how to set up such a timer, but not how to change its frequency if this has already been set.
After not getting very far by looking at FspTimer.h and FspTimer.cpp on github, I ended up doing what seemed sensible to me, which is shown in the sketch below.
With this sketch, I type the frequency into the serial port and the board LED flashes at this frequency. I can re-enter the frequency and the LED will flash at the new frequency.
The sketch works fine, but I have the following questions:

  1. Is what I have done correct?
  2. Is there a more elegant way of doing this?
  3. I understand what the functions begin/end do. But could someone be so kind as to explain the purpose of the open/close and start/stop functions? What about setup_overflow_irq()?
#include <FspTimer.h>

FspTimer FTimer;
int iLed =  LED_BUILTIN;
volatile int iLedState;


void vTimerCallback(timer_callback_args_t __attribute((unused)) *p_args) {
  if (iLedState == LOW) {
    digitalWrite(iLed, HIGH);
    iLedState = HIGH;
  }
  else {
    digitalWrite(iLed, LOW);
    iLedState = LOW;
  }
}


bool bBeginTimer(float rate) {
  /* This is from                                                                     */
  /* https://www.pschatzmann.ch/home/2023/07/01/under-the-hood-arduino-uno-r4-timers/ */
    uint8_t timer_type = GPT_TIMER;
  int8_t tindex = FspTimer::get_available_timer(timer_type);
  if (tindex < 0){
    tindex = FspTimer::get_available_timer(timer_type, true);
  }
  if (tindex < 0){
    return false;
  }

  FspTimer::force_use_of_pwm_reserved_timer();

  if(!FTimer.begin(TIMER_MODE_PERIODIC, timer_type, tindex, rate, 0.0f, vTimerCallback)){
    return false;
  }

  if (!FTimer.setup_overflow_irq()){
    return false;
  }

  if (!FTimer.open()){
    return false;
  }

  if (!FTimer.start()){
    return false;
  }
  return true;
}


bool bHaltTimer(void) {
  if (!FTimer.stop()){
    return false;
  }

  /* Skipping Ftimer.close() as it is already included in FspTimer::end() in */
  /* FspTimer.cpp                                                            */
  /* if (!FTimer.close()){                                                   */
  /* return false;                                                           */
  /* }                                                                       */

  FTimer.end();
  return true;
}


void setup() {
  pinMode(iLed, OUTPUT);

   /* start serial port at 9600 bps and wait for port to open: */
  Serial.begin(9600);
  /* wait for serial port to connect. Needed for native USB port only */
  while (!Serial) {}

  Serial.println("Enter frequency in Hz");

  /* Start the timer with an arbitrary frequency (1Hz) */
  bBeginTimer(1);
}


void loop() {
  String sInput;
  float fInput;
  if (Serial.available()) {
    sInput = Serial.readStringUntil('\n');
    fInput = sInput.toFloat();
    if (fInput > 0.00) {
      Serial.println(fInput);
      bHaltTimer();
      bBeginTimer(fInput);
    }
    else {
      Serial.println("Erroneous value entered");
    }
  }
}

Any assistance would be thoroughly appreciated! Many thanks.

It's working, right?

What counts as "elegant" is up to you, but it results in shorter code.

bool bBeginTimer(float rate) {
  ...// omitted

  if(!FTimer.begin(TIMER_MODE_PERIODIC, timer_type, tindex, rate, 0.0f, vTimerCallback)){
    return false;
  }

  if (!FTimer.open()){
    return false;
  }

  return FTimer.setup_overflow_irq();
}

Or do you want to make a class as including a blinking LED?

Please refer to the FSP documentation:

The code for setup_overflow_irq() is as follows:

/* -------------------------------------------------------------------------- */
bool FspTimer::setup_overflow_irq(uint8_t priority /*= 12*/,  Irq_f isr_fnc /*= nullptr*/ ) {
/* -------------------------------------------------------------------------- */
    
    TimerIrqCfg_t cfg = get_cfg_for_irq();
    /* that is due to the fact that when the timer is opened the configuration
       of the interrupt is ignore by FSP, this is usually not a problem
       if first you set up the timer and then open and start it 
       in some case, for example you want to set up an interrupt via a PWM timer
       you need to call begin in advance (otherwise timer is not correctly populated) 
       but begin open and start the timer*/
    bool was_opened = is_opened();

    if(was_opened) {
        close();
    }

    bool rv = IRQManager::getInstance().addTimerOverflow(cfg,isr_fnc);

    if(rv) {
        timer_cfg.cycle_end_ipl = priority;
    }
    else {
        timer_cfg.cycle_end_irq = FSP_INVALID_VECTOR;    
    }

    if(was_opened) {
        open();
        start();
    }
    return rv;
}

I'm not an expert on this, but IRQManager coordinates the Interrupt Controller Unit and the Event LInk Controller, and sets up interrupts and registers handler functions.

For information about the ICU and ELC, see the "Renesas RA4M1 Group User's Manual: Hardware".

embeddedkiddie, thank you for pointing me in the right direction! Goodness, I have a lot of reading to do…