/** ****************************************************************************** * @file bench_time.h * @brief Заголовочный файл для измерения времени между событиями ****************************************************************************** * @addtogroup BENCH_TIME Time measurement * @ingroup MYLIBS_DEFINES * @brief Библиотека для измерения времени/тиков между событиями * @details Поддерживает: - Многоканальные измерения (несколько независимых таймеров) - Платформонезависимый интерфейс - Измерение в тиках или временных единицах - Статистику измерений (мин/макс/среднее) - Настраиваемый размер тиков для каждого канала Параметры для конфигурации: - @ref BENCH_TIME_ENABLE - Включить бенч времени - @ref BENCH_TIME_MAX_CHANNELS - Максимальное количество каналов измерения (по умолчанию 8) @par Пример использования: @code #include "bench_time.h" // Инициализация BenchTime_Init(); // Измерение с SysTick BenchTime_Start(0, HAL_GetTick, 0xFFFFFFFF); some_function(); uint32_t time = BenchTime_End(0, HAL_GetTick); // Измерение с TIM2 (16-бит) BenchTime_Start(1, TIM2->CNT, 0xFFFF); fast_function(); uint32_t time2 = BenchTime_End(1, TIM2->CNT); // Измерение с DWT цикловым счетчиком BenchTime_Start(2, DWT->CYCCNT, 0xFFFFFFFF); critical_function(); uint32_t cycles = BenchTime_End(2, DWT->CYCCNT); // Многоканальное измерение BenchTime_Start(0, HAL_GetTick, 1000); // общее время BenchTime_Start(1, TIM3->CNT, 500); // часть 1 // ... код 1 uint32_t part1 = BenchTime_End(1, TIM3->CNT); BenchTime_Start(2, TIM4->CNT, 200); // часть 2 // ... код 2 uint32_t part2 = BenchTime_End(2, TIM4->CNT); uint32_t total = BenchTime_End(0, HAL_GetTick); // общее время // Статистика uint32_t min_time = BenchTime_GetMin(0); uint32_t max_time = BenchTime_GetMax(0); uint32_t avg_time = BenchTime_GetAverage(0); uint32_t count = BenchTime_GetCount(0); @endcode * @{ *****************************************************************************/ #ifndef __BENCH_TIME_H_ #define __BENCH_TIME_H_ #include "mylibs_defs.h" #include #ifdef BENCH_TIME_ENABLE // Конфигурация библиотеки #ifndef BENCH_TIME_MAX_CHANNELS #define BENCH_TIME_MAX_CHANNELS 8 ///< Максимальное количество каналов измерения #endif /** * @brief Структура статистики измерений */ typedef struct { uint32_t min_ticks; ///< Минимальное время в тиках uint32_t max_ticks; ///< Максимальное время в тиках uint32_t total_ticks; ///< Суммарное время в тиках uint32_t count; ///< Количество измерений uint32_t last_ticks; ///< Последнее измеренное время } BenchTimeStats_t; /** * @brief Структура канала измерения */ typedef struct { uint32_t start_tick; ///< Время старта в тиках uint32_t tick_period; ///< Период тиков для переполнения uint32_t is_running; ///< Флаг активного измерения BenchTimeStats_t stats; ///< Статистика измерений } BenchTimeChannel_t; /** * @brief Основная структура менеджера измерений */ typedef struct { BenchTimeChannel_t channels[BENCH_TIME_MAX_CHANNELS]; ///< Каналы измерения } BenchTime_t; static BenchTime_t hbt = {0}; ///< Внутренний экземпляр /** * @brief Инициализация системы измерения времени */ static inline void BenchTime_Init(void) { for (int i = 0; i < BENCH_TIME_MAX_CHANNELS; i++) { hbt.channels[i].start_tick = 0; hbt.channels[i].tick_period = 0xFFFFFFFF; hbt.channels[i].is_running = 0; hbt.channels[i].stats.min_ticks = 0xFFFFFFFF; hbt.channels[i].stats.max_ticks = 0; hbt.channels[i].stats.total_ticks = 0; hbt.channels[i].stats.count = 0; hbt.channels[i].stats.last_ticks = 0; } } /** * @brief Начало измерения на указанном канале * @param channel Номер канала (0..BENCH_TIME_MAX_CHANNELS-1) * @param ticks Источник тиков (например: HAL_GetTick(), TIM2->CNT, DWT->CYCCNT) * @param tick_period Период тиков для переполнения * @return 1 - успех, 0 - ошибка */ static inline uint32_t BenchTime_Start(uint8_t channel, uint32_t ticks, uint32_t tick_period) { if (channel >= BENCH_TIME_MAX_CHANNELS) return 0; if (hbt.channels[channel].is_running) return 0; hbt.channels[channel].start_tick = ticks; hbt.channels[channel].tick_period = tick_period; hbt.channels[channel].is_running = 1; return 1; } /** * @brief Окончание измерения на указанном канале * @param channel Номер канала (0..BENCH_TIME_MAX_CHANNELS-1) * @param ticks Источник тиков (должен быть тот же что в Start) * @return Измеренное время в тиках, 0 - в случае ошибки */ static inline uint32_t BenchTime_End(uint8_t channel, uint32_t ticks) { if (channel >= BENCH_TIME_MAX_CHANNELS) return 0; if (!hbt.channels[channel].is_running) return 0; uint32_t end_tick = ticks; uint32_t start_tick = hbt.channels[channel].start_tick; uint32_t tick_period = hbt.channels[channel].tick_period; uint32_t elapsed_ticks; if (end_tick >= start_tick) { elapsed_ticks = end_tick - start_tick; } else { elapsed_ticks = (tick_period - start_tick) + end_tick + 1; } if (elapsed_ticks > tick_period) { elapsed_ticks = tick_period; } hbt.channels[channel].is_running = 0; // Обновление статистики BenchTimeStats_t* stats = &hbt.channels[channel].stats; stats->last_ticks = elapsed_ticks; if (elapsed_ticks < stats->min_ticks) { stats->min_ticks = elapsed_ticks; } if (elapsed_ticks > stats->max_ticks) { stats->max_ticks = elapsed_ticks; } stats->total_ticks += elapsed_ticks; stats->count++; return elapsed_ticks; } /** * @brief Получение минимального времени измерения */ static inline uint32_t BenchTime_GetMin(uint8_t channel) { if (channel >= BENCH_TIME_MAX_CHANNELS) return 0; return hbt.channels[channel].stats.min_ticks; } /** * @brief Получение максимального времени измерения */ static inline uint32_t BenchTime_GetMax(uint8_t channel) { if (channel >= BENCH_TIME_MAX_CHANNELS) return 0; return hbt.channels[channel].stats.max_ticks; } /** * @brief Получение среднего времени измерения */ static inline uint32_t BenchTime_GetAverage(uint8_t channel) { if (channel >= BENCH_TIME_MAX_CHANNELS) return 0; BenchTimeStats_t* stats = &hbt.channels[channel].stats; if (stats->count == 0) return 0; return stats->total_ticks / stats->count; } /** * @brief Получение количества измерений */ static inline uint32_t BenchTime_GetCount(uint8_t channel) { if (channel >= BENCH_TIME_MAX_CHANNELS) return 0; return hbt.channels[channel].stats.count; } /** * @brief Получение последнего измеренного времени */ static inline uint32_t BenchTime_GetLast(uint8_t channel) { if (channel >= BENCH_TIME_MAX_CHANNELS) return 0; return hbt.channels[channel].stats.last_ticks; } /** * @brief Сброс статистики для канала */ static inline void BenchTime_ResetStats(uint8_t channel) { if (channel >= BENCH_TIME_MAX_CHANNELS) return; BenchTimeStats_t* stats = &hbt.channels[channel].stats; stats->min_ticks = 0xFFFFFFFF; stats->max_ticks = 0; stats->total_ticks = 0; stats->count = 0; stats->last_ticks = 0; } #else //BENCH_TIME_ENABLE #define BenchTime_Init() #define BenchTime_Start(channel, ticks, tick_period) 0 #define BenchTime_End(channel, ticks) 0 #define BenchTime_GetMin(channel) 0 #define BenchTime_GetMax(channel) 0 #define BenchTime_GetAverage(channel) 0 #define BenchTime_GetCount(channel) 0 #define BenchTime_GetLast(channel) 0 #define BenchTime_ResetStats(channel) #endif //BENCH_TIME_ENABLE #endif // __BENCH_TIME_H_ /** BENCH_TIME * @} */