mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-10-30 22:51:41 +01:00 
			
		
		
		
	
		
			
	
	
		
			47 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
		
		
			
		
	
	
			47 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
|   | # GPTimer Driver Design
 | ||
|  | 
 | ||
|  | ## State Transition
 | ||
|  | 
 | ||
|  | > State transition is achieved by using the primitives provided by `<stdatomic.h>`.
 | ||
|  | 
 | ||
|  | ```mermaid | ||
|  | 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. | ||
|  | 
 | ||
|  | ```mermaid | ||
|  | 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. |