The BasePeriodicTimer class provides a comprehensive periodic timer abstraction that serves as the
unified interface for all high-precision timing operations in the HardFOC system.
It supports microsecond resolution, callback-based notifications,
and works across different timer implementations.
β¨ Key Features
β° Microsecond Resolution - High-precision timing down to microseconds
π Callback Support - Event-driven timer notifications
π Dynamic Period Control - Change period during operation
π‘οΈ Robust Error Handling - Comprehensive validation and error reporting
π Platform Agnostic - Works with hardware and software timers
π Statistics & Diagnostics - Built-in monitoring and health reporting
π§΅ Thread Safe - Designed for multi-threaded applications
β‘ Low Overhead - Optimized for real-time applications
/**
* @brief Initialize the timer hardware/resources
* @return hf_timer_err_t error code
*
* π Sets up timer hardware, configures callbacks, and prepares for operation.
* Must be called before any timer operations.
*
* @example
* EspPeriodicTimer timer(TIMER_GROUP_0, TIMER_0);
* if (timer.Initialize() == hf_timer_err_t::TIMER_SUCCESS) {
* // Timer ready for use
* }
*/virtualhf_timer_err_tInitialize()noexcept=0;/**
* @brief Deinitialize the timer and free resources
* @return hf_timer_err_t error code
*
* π§Ή Cleanly shuts down timer hardware and releases resources.
*/virtualhf_timer_err_tDeinitialize()noexcept=0;/**
* @brief Check if timer is initialized
* @return true if initialized, false otherwise
*
* β Query initialization status without side effects.
*/boolIsInitialized()constnoexcept;/**
* @brief Check if timer is currently running
* @return true if running, false otherwise
*
* β Query running status without side effects.
*/boolIsRunning()constnoexcept;
/**
* @brief Start the periodic timer with specified period
* @param period_us Timer period in microseconds
* @return hf_timer_err_t error code
*
* β° Starts the timer with the specified period.
* Callback will be invoked at each period.
*
* @example
* hf_timer_err_t result = timer.Start(1000000); // 1 second period
* if (result != hf_timer_err_t::TIMER_SUCCESS) {
* printf("Timer start failed: %s\n", HfTimerErrToString(result));
* }
*/virtualhf_timer_err_tStart(uint64_tperiod_us)noexcept=0;/**
* @brief Stop the periodic timer
* @return hf_timer_err_t error code
*
* βΈοΈ Stops the timer and cancels all pending callbacks.
*
* @example
* hf_timer_err_t result = timer.Stop();
* if (result == hf_timer_err_t::TIMER_SUCCESS) {
* printf("Timer stopped successfully\n");
* }
*/virtualhf_timer_err_tStop()noexcept=0;/**
* @brief Change the timer period while running
* @param period_us New timer period in microseconds
* @return hf_timer_err_t error code
*
* π Changes the timer period without stopping and restarting.
*
* @example
* // Change from 1 second to 500ms while running
* timer.SetPeriod(500000);
*/virtualhf_timer_err_tSetPeriod(uint64_tperiod_us)noexcept=0;/**
* @brief Get the current timer period
* @param period_us Reference to store the current period
* @return hf_timer_err_t error code
*
* π Retrieves the current timer period.
*
* @example
* uint64_t current_period;
* if (timer.GetPeriod(current_period) == hf_timer_err_t::TIMER_SUCCESS) {
* printf("Current period: %llu ΞΌs\n", current_period);
* }
*/virtualhf_timer_err_tGetPeriod(uint64_t&period_us)noexcept=0;
/**
* @brief Set callback function for timer events
* @param callback Callback function to invoke
* @param user_data User data to pass to callback (optional)
* @return hf_timer_err_t error code
*
* π Sets the callback function that will be invoked at each timer period.
*
* @example
* void on_timer_tick(void* user_data) {
* printf("Timer tick! User data: %p\n", user_data);
* // Handle timer event
* }
*
* timer.SetCallback(on_timer_tick, nullptr);
*/hf_timer_err_tSetCallback(hf_timer_callback_tcallback,void*user_data=nullptr)noexcept;/**
* @brief Get current user data pointer
* @return User data pointer
*
* π Returns the user data associated with the timer callback.
*/void*GetUserData()constnoexcept;/**
* @brief Check if timer has a valid callback
* @return true if callback is set, false otherwise
*
* β Checks if a callback function has been set.
*/boolHasValidCallback()constnoexcept;
/**
* @brief Get description of this timer implementation
* @return Description string
*
* π Returns a human-readable description of this timer implementation.
*/virtualconstchar*GetDescription()constnoexcept=0;/**
* @brief Get minimum supported timer period
* @return Minimum period in microseconds
*
* π Returns the minimum supported timer period for this hardware.
*/virtualuint64_tGetMinPeriod()constnoexcept=0;/**
* @brief Get maximum supported timer period
* @return Maximum period in microseconds
*
* π Returns the maximum supported timer period for this hardware.
*/virtualuint64_tGetMaxPeriod()constnoexcept=0;/**
* @brief Get timer resolution
* @return Timer resolution in microseconds
*
* π Returns the timer resolution (minimum time increment).
*/virtualuint64_tGetResolution()constnoexcept=0;
structhf_timer_statistics_t{uint32_ttotalStarts;///< Total timer startsuint32_ttotalStops;///< Total timer stopsuint32_tcallbackExecutions;///< Number of callback executionsuint32_tmissedCallbacks;///< Number of missed callbacksuint32_taverageCallbackTimeUs;///< Average callback execution time (microseconds)uint32_tmaxCallbackTimeUs;///< Maximum callback execution timeuint32_tminCallbackTimeUs;///< Minimum callback execution timeuint64_ttotalRunningTimeUs;///< Total running time in microseconds};
π Timer Diagnostics Structure
1
2
3
4
5
6
7
8
9
10
structhf_timer_diagnostics_t{booltimerHealthy;///< Overall timer health statushf_timer_err_tlastErrorCode;///< Last error codeuint32_tlastErrorTimestamp;///< Last error timestampuint32_tconsecutiveErrors;///< Consecutive error countbooltimerInitialized;///< Timer initialization statusbooltimerRunning;///< Timer running statusuint64_tcurrentPeriodUs;///< Current timer period in microsecondsuint64_ttimerResolutionUs;///< Timer resolution in microseconds};
π Timer Stats Structure
1
2
3
4
5
6
7
8
structhf_timer_stats_t{uint64_tstart_count;///< Number of timer startsuint64_tstop_count;///< Number of timer stopsuint64_tcallback_count;///< Number of callback executionsuint64_tmissed_callbacks;///< Number of missed callbackshf_timer_err_tlast_error;///< Last error encounteredhf_timestamp_us_tlast_start_us;///< Timestamp of last start};
#include"mcu/esp32/EspPeriodicTimer.h"classControlLoop{private:EspPeriodicTimertimer*;floatsetpoint*;floatcurrent_value*;floatkp*,ki*,kd*;floatintegral*;floatlast_error*;public:ControlLoop():timer*(TIMER_GROUP_0,TIMER_0),setpoint*(0.0f),current_value*(0.0f),kp*(1.0f),ki*(0.1f),kd*(0.01f),integral*(0.0f),last_error*(0.0f){}boolinitialize(){// Initialize timerif(timer*.Initialize()!=hf_timer_err_t::TIMER_SUCCESS){printf("β Control loop timer initialization failed\n");returnfalse;}// Set callbacktimer*.SetCallback([](void*user_data){static_cast<ControlLoop*>(user_data)->control_step();},this);returntrue;}voidstart(floatfrequency_hz){uint64_tperiod_us=static_cast<uint64_t>(1000000.0f/frequency_hz);hf_timer_err_tresult=timer*.Start(period_us);if(result==hf_timer_err_t::TIMER_SUCCESS){printf("β Control loop started at %.1f Hz\n",frequency_hz);}else{printf("β Control loop start failed: %s\n",HfTimerErrToString(result));}}voidstop(){timer*.Stop();printf("βΈοΈ Control loop stopped\n");}voidset_setpoint(floatsetpoint){setpoint*=setpoint;}voidset_current_value(floatvalue){current_value*=value;}voidset_gains(floatkp,floatki,floatkd){kp*=kp;ki*=ki;kd*=kd;integral*=0.0f;// Reset integral on gain change}private:voidcontrol_step(){// Calculate errorfloaterror=setpoint*-current_value*;// PID controlfloatproportional=kp**error;integral*+=ki**error;floatderivative=kd**(error-last_error*);floatoutput=proportional+integral*+derivative;// Apply output (example: motor speed)apply_control_output(output);// Update for next iterationlast_error*=error;// Optional: print control infostaticuint32_tstep_count=0;if(++step_count%100==0){// Print every 100 stepsprintf("π― Control - Setpoint: %.2f, Current: %.2f, Output: %.2f\n",setpoint*,current_value*,output);}}voidapply_control_output(floatoutput){// Apply control output to actuator// This is just an example - implement based on your hardwareprintf("β‘ Control output: %.2f\n",output);}};voidcontrol_loop_example(){ControlLoopcontroller;if(!controller.initialize()){printf("β Controller initialization failed\n");return;}// Configure control parameterscontroller.set_gains(2.0f,0.5f,0.1f);controller.set_setpoint(100.0f);// Start control loop at 100 Hzcontroller.start(100.0f);// Simulate changing setpointvTaskDelay(pdMS_TO_TICKS(5000));// Wait 5 secondscontroller.set_setpoint(200.0f);vTaskDelay(pdMS_TO_TICKS(5000));// Wait 5 secondscontroller.stop();}
#include"mcu/esp32/EspPeriodicTimer.h"classAdaptiveTimer{private:EspPeriodicTimertimer*;uint64_tcurrent_period*;uint64_tmin_period*;uint64_tmax_period*;uint32_tload_factor*;public:AdaptiveTimer(uint64_tmin_period_us=1000,uint64_tmax_period_us=1000000):timer*(TIMER_GROUP_0,TIMER_0),current_period*(100000),min_period*(min_period_us),max_period*(max_period_us),load_factor*(50){}boolinitialize(){if(timer*.Initialize()!=hf_timer_err_t::TIMER_SUCCESS){returnfalse;}timer*.SetCallback([](void*user_data){static_cast<AdaptiveTimer*>(user_data)->adaptive_step();},this);returntrue;}voidstart(){hf_timer_err_tresult=timer*.Start(current_period*);if(result==hf_timer_err_t::TIMER_SUCCESS){printf("β Adaptive timer started with period %llu ΞΌs\n",current_period*);}}voidstop(){timer*.Stop();}voidset_load_factor(uint32_tfactor){load_factor*=std::min(factor,100u);// Clamp to 0-100adjust_period();}uint64_tget_current_period()const{returncurrent_period*;}private:voidadaptive_step(){// Simulate system load measurementuint32_tcurrent_load=measure_system_load();// Adjust load factor based on current loadif(current_load>80){load_factor*=std::min(load_factor*+5,100u);}elseif(current_load<20){load_factor*=std::max(load_factor*-5,0u);}// Adjust period based on load factoradjust_period();// Perform periodic taskperform_task();}voidadjust_period(){// Calculate new period based on load factor// Higher load = longer period (slower execution)uint64_tnew_period=min_period*+((max_period*-min_period*)*load_factor*)/100;if(new_period!=current_period*){current_period*=new_period;timer*.SetPeriod(current_period*);printf("π Period adjusted to %llu ΞΌs (load: %u%%)\n",current_period*,load_factor*);}}uint32_tmeasure_system_load(){// Simulate system load measurement// Replace with actual load measurementstaticuint32_tload=50;load+=(rand()%21)-10;// Random change Β±10if(load>100)load=100;if(load<0)load=0;returnload;}voidperform_task(){// Simulate periodic task executionstaticuint32_ttask_count=0;task_count++;if(task_count%100==0){printf("β‘ Task executed %u times (period: %llu ΞΌs)\n",task_count,current_period*);}}};voidadaptive_timer_example(){AdaptiveTimertimer(1000,100000);// 1ms to 100ms rangeif(!timer.initialize()){printf("β Adaptive timer initialization failed\n");return;}timer.start();// Simulate changing system loadfor(inti=0;i<10;i++){vTaskDelay(pdMS_TO_TICKS(1000));// Simulate high loadtimer.set_load_factor(80);vTaskDelay(pdMS_TO_TICKS(1000));// Simulate low loadtimer.set_load_factor(20);}timer.stop();}
// β Always check initializationif(timer.Initialize()!=hf_timer_err_t::TIMER_SUCCESS){printf("β Timer initialization failed\n");returnfalse;}// β Use appropriate period rangesuint64_tmin_period=timer.GetMinPeriod();uint64_tmax_period=timer.GetMaxPeriod();uint64_tperiod=std::clamp(desired_period,min_period,max_period);// β Handle all error codeshf_timer_err_tresult=timer.Start(period);if(result!=hf_timer_err_t::TIMER_SUCCESS){printf("β οΈ Timer Error: %s\n",HfTimerErrToString(result));// Handle specific error typesif(result==hf_timer_err_t::TIMER_ERR_INVALID_PERIOD){// Period out of range}elseif(result==hf_timer_err_t::TIMER_ERR_ALREADY_RUNNING){// Timer already running}}// β Set callback before starting timertimer.SetCallback(on_timer_tick,user_data);timer.Start(period);// β Keep callbacks short and efficientvoidon_timer_tick(void*user_data){// Quick operations only// Avoid blocking operations// Use queues for longer tasks}// β Monitor timer statisticsuint64_tcallback_count,missed_callbacks;hf_timer_err_tlast_error;if(timer.GetStats(callback_count,missed_callbacks,last_error)==hf_timer_err_t::TIMER_SUCCESS){if(missed_callbacks>0){printf("β οΈ Missed callbacks detected: %llu\n",missed_callbacks);}}
// π Use appropriate period for application// Too short: may cause missed callbacks// Too long: may not meet timing requirements// π Keep callbacks lightweight// Use queues for longer operations// Avoid memory allocation in callbacks// π Use hardware timers when available// Hardware timers are more precise than software timers// π Monitor missed callbacks// High missed callback count indicates system overload// π Use appropriate timer resolution// Don't use 1ΞΌs resolution for 1-second periods// π Consider timer priority// High-priority timers for critical operations// Lower priority for non-critical operations