GPTimer Frequency Not As Expected

zuorunze
Posts: 2
Joined: Mon Oct 06, 2025 5:39 pm

GPTimer Frequency Not As Expected

Postby zuorunze » Mon Oct 06, 2025 6:04 pm

Hi!

I'm developing a custom PWM driver based on the GPTimer.

Chip: ESP32S3
Borad: Adafruit ESP32S3 QTPY no psram

I tested a version on Arduino esp32, and it works as expected:

Code: Select all

// Set timer frequency to 1Mhz
  pctrl_timer = timerBegin(timerfreq);
  timerAttachInterrupt(pctrl_timer, &VEMA_PWM_PCTRL);
  timerAlarm(pctrl_timer, (timerfreq >> pwm_bits) / pwm_freq, true, 0);
where timerfreq is 40,000,000; pwm_bits is 8; pwm_freq is 300.

However, when I tried to migrate the project to ESP-IDF, the timer considerablly slowed down

Code: Select all

uint64_t resolution_hz = 40000000;
	uint64_t alarm_count = 500;
	uint64_t reload_count = 0;

	gptimer_config_t timer_config = {
        .clk_src = GPTIMER_CLK_SRC_APB,
        .direction = GPTIMER_COUNT_UP,
        .resolution_hz = resolution_hz,
		.intr_priority = 3,
		.flags.intr_shared = 0,
		.flags.allow_pd = 0,
    	.flags.backup_before_sleep = 0,
    };
	ESP_ERROR_CHECK(gptimer_new_timer(&timer_config, &gptimer));
	gptimer_event_callbacks_t cbs = {
        .on_alarm = PWM_isr,
    };
	ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &cbs, NULL));
	ESP_LOGI(TAG, "Enable timer");
    ESP_ERROR_CHECK(gptimer_enable(gptimer));

	ESP_LOGI(TAG, "Start timer, stop it at alarm event");
    gptimer_alarm_config_t alarm_config1 = {
        .reload_count = reload_count,
        .alarm_count = alarm_count,
        .flags.auto_reload_on_alarm = true,
    };
	ESP_ERROR_CHECK(gptimer_set_raw_count(gptimer, 0));
    ESP_ERROR_CHECK(gptimer_set_alarm_action(gptimer, &alarm_config1));
    ESP_ERROR_CHECK(gptimer_start(gptimer));

The ISR:

Code: Select all

static bool IRAM_ATTR PWM_isr(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data) {


  // increment the PWM counter
  // since this is a 8 bit unsigned integer
  // it will automatically overflow and go back to 0 after hitting max
  vema_pwm_ptr++;
  // here, we use v1 duty cycle as inlet duty cycle
  if (vema_pwm_ptr > 120) {
    // pressure too low, turn off outlet valve
    gpio_set_level(V_OUT, LOW);
	gpio_set_level(V_IN, LOW);

  } else {
	gpio_set_level(V_OUT, HIGH);
	gpio_set_level(V_IN, HIGH);
  }

  return true;
}
vema_pwm_ptr is an 8-bit number; it automatically overflows

The Arduino code gives me about ~300Hz, the ESP-idf code gives me about ~311Hz
But notice the alarm_count for each is very different. Arduino alarm_count = 16666; ESP = 500

I wonder what might have caused this difference?
I have already changed FreeRTOS tick 100->1000, and CPU frequency is 240MHz.

Many thanks for any help!!!!

MicroController
Posts: 2663
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: GPTimer Frequency Not As Expected

Postby MicroController » Tue Oct 07, 2025 2:30 pm

Code: Select all

// Set timer frequency to 1Mhz
  pctrl_timer = timerBegin(timerfreq);
...
where timerfreq is 40,000,000;
Are you sure about the 40MHz?

I don't see an actual error in your code, but I'd suggest to
a) use hardware to generate PWM signals (LEDC), or
b) if using a timer, make the alarm only trigger on the edges of the PWM signal. Your current code triggers the ISR 256x where it should be only 2x. You're trying to handle 80000 interrupts per second! That's way too much - and you only need 600 per second.
Consider letting the timer count down and trigger the alarm when it reaches 0. This way, you can just gptimer_set_raw_count() at any point to set the time until the next alarm interrupt.

zuorunze
Posts: 2
Joined: Mon Oct 06, 2025 5:39 pm

Re: GPTimer Frequency Not As Expected

Postby zuorunze » Tue Oct 07, 2025 6:24 pm

Thanks for checking it out!

I'm actually dumb that (40M >> 8) / 300 is actually close to 500.
I was mistaking >> 8 as divide 8 instead of divide 2^8.

The code is working as expected. Sorry for the confusion

Who is online

Users browsing this forum: No registered users and 1 guest