258 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			258 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/**
 | 
						||
******************************************************************************
 | 
						||
* @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
 | 
						||
  * @}
 | 
						||
  */ |