STM32_ExtendedLibs/MyLibs/Inc/bench_time.h

258 lines
8.8 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
******************************************************************************
* @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 <stdint.h>
#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
* @}
*/