esp-idf/components/esp_driver_gptimer
Wu Zheng Hui 6abe40e590 Merge branch 'feature/optimize_esp32p4_active_power_eco1' into 'master'
feat(system): Optimize esp32p4 active state  power consumption

Closes PM-103 and IDF-7688

See merge request espressif/esp-idf!32950
2024-09-11 23:15:29 +08:00
..
include driver(gptimer): support software triggered GPTimer retention test 2024-08-20 10:52:17 +08:00
src feat(esp_hw_support): add clk tree source gate management api 2024-09-11 10:53:01 +08:00
test_apps fix(ci): take some actions to pass ci 2024-09-10 19:37:50 +08:00
CMakeLists.txt refactor(gptimer): sleep retention code clean up 2024-06-18 09:59:12 +08:00
Kconfig fix(drivers): fix typos found by codespell 2024-03-28 10:01:27 +08:00
linker.lf refactor(gptimer): refactor gptimer driver into a component 2023-11-06 17:09:31 +08:00
README.md refactor(gptimer): refactor gptimer driver into a component 2023-11-06 17:09:31 +08:00

GPTimer Driver Design

State Transition

State transition is achieved by using the primitives provided by <stdatomic.h>.

stateDiagram-v2
    [*] --> init: gptimer_new_timer
    init --> enable: gptimer_enable
    enable --> init: gptimer_disable
    enable --> run: gptimer_start*
    run --> enable: gptimer_stop*
    init --> [*]: gptimer_del_timer

Other functions won't change the driver state. The functions above labeled with * are allowed to be used in the interrupt context.

Concurrency

There might be race conditions when the user calls the APIs from a thread and interrupt at the same time. e.g. a Task is just running the gptimer_start, and suddenly an interrupt occurs, where the user calls gptimer_stop for the same timer handle. Which is possible to make a "stopped" timer continue to run if the interrupt is returned before the Task.

stateDiagram-v2
    state Race-Condition {
        Thread --> gptimer_start
        state gptimer_start {
            state is_enabled <<choice>>
            [*] --> is_enabled: Enabled?
            is_enabled --> run_wait: yes
            is_enabled --> [*] : no
            run_wait --> run: call HAL/LL functions to start timer
            }
        --
        Interrupt --> gptimer_stop
        state gptimer_stop {
            state is_running <<choice>>
            [*] --> is_running: Running?
            is_running --> enable_wait: yes
            is_running --> [*] : no
            enable_wait --> enable: call HAL/LL functions to stop timer
        }
    }

By introducing a "middle" state like run_wait and enable_wait, we make sure that the timer is in a safe state before we start/stop it. And if the state is invalid, it can return an error code to the user.