espressif/qemu

Alarm from general purpose timer not triggered when too old (QEMU-104)

blaizard opened this issue · 0 comments

The timer interrupt for the esp32 machine doesn't behave the same as the physical target.
When the alarm of a general purpose timer is set and the alarm value is lower than the actual counter, the interrupt should be triggered. This is stated in the documentation, from https://docs.espressif.com/projects/esp-idf/en/v5.0.1/esp32/api-reference/peripherals/gptimer.html#set-up-alarm-action

If an alarm value is set and the timer has already exceeded this value, the alarm will be triggered immediately.

This work fine on a physical esp32 but not on QEMU. Here is a sample code to reproduce the issue:

static bool testCallback(::gptimer_handle_t, const ::gptimer_alarm_event_data_t* edata, void* userCtx)
{
    ::esp_rom_printf("ISR triggered, counter=%llu\r\n", edata->count_value);
    std::atomic<uint64_t>& counter = *static_cast<std::atomic<uint64_t>*>(userCtx);
    counter.store(edata->count_value);
    return false;
}

::gptimer_handle_t gptimer_;

::gptimer_config_t config{};
config.clk_src = GPTIMER_CLK_SRC_APB;
config.direction = GPTIMER_COUNT_UP;
config.resolution_hz = 10 * 1000; // 0.1ms
config.flags.intr_shared = false;
::gptimer_new_timer(&config, &gptimer_);

::gptimer_event_callbacks_t callback{
    .on_alarm = testCallback
};
std::atomic<uint64_t> counter{0};
::gptimer_register_event_callbacks(gptimer_, &callback, &counter);

::gptimer_enable(gptimer_);

::gptimer_start(gptimer_);

vTaskDelay(pdMS_TO_TICKS(1000));

::gptimer_alarm_config_t alarm{};
alarm.alarm_count = 10;
::gptimer_set_alarm_action(gptimer_, &alarm);

::esp_rom_printf("waiting...\r\n");
while (counter.load() == 0);
::esp_rom_printf("counter=%llu\r\n", counter.load());

Running the exact same binary on the QEMU or the real physical esp32, I get different behavior.
On QEMU, it only prints:

waiting...

while on the physical esp32:

ISR triggered, counter=9982
waiting...
counter=9982

Note that the expected behavior is the physical esp32. I initially raised this issue as part of the IDF github (espressif/esp-idf#10877) but narrow it down to QEMU.