Compare commits
6 Commits
pre-releas
...
release
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd45847d5d | ||
|
|
cb3783bd07 | ||
|
|
795ebbd220 | ||
|
|
eff64709bc | ||
|
|
6d1a5c8f71 | ||
| f46fa9b4ac |
@@ -1,125 +0,0 @@
|
||||
/**
|
||||
**************************************************************************
|
||||
* @file mylibs_include.h
|
||||
* @brief Заголочный файл для всех библиотек
|
||||
**************************************************************************
|
||||
* @details
|
||||
Здесь нужно собрать библиотеки и дефайны, которые должны быть видны во всем проекте,
|
||||
чтобы не подключать 100 инклюдов в каждом ".c" файле
|
||||
**************************************************************************
|
||||
* @defgroup MYLIBS_ALL My Libs
|
||||
* @brief Все используемые MyLibs библиотеки
|
||||
* @details
|
||||
Для подключения библиотеки необходимо:
|
||||
- Сконфигурировать mylibs_config.h:
|
||||
- Подключить заголовочный файл HAL библиотеки конкретного МК (напр. stm32f4xx_hal.h)
|
||||
- Подключить другие заголовочные файлы которые общие для всего проекта и должны быть видны
|
||||
-
|
||||
- Подключить mylibs_include.h туда, где необходим доступ к библиотекам.
|
||||
|
||||
* @defgroup MYLIBS_PERIPHERAL Peripheral
|
||||
* @ingroup MYLIBS_ALL
|
||||
* @brief Модули для управления периферией
|
||||
*
|
||||
*************************************************************************/
|
||||
#ifndef __MYLIBS_INCLUDE_H_
|
||||
#define __MYLIBS_INCLUDE_H_
|
||||
|
||||
#include "mylibs_defs.h"
|
||||
|
||||
|
||||
#ifdef ARM_MATH_CM4
|
||||
#include "arm_math.h"
|
||||
#else
|
||||
#include "math.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef INCLUDE_BIT_ACCESS_LIB
|
||||
#include "bit_access.h"
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_TRACKERS_LIB
|
||||
#include "trackers.h"
|
||||
#else
|
||||
#define TrackerTypeDef(num_user_vars) void *
|
||||
#define num_of_usercnts(_user_) 0
|
||||
#define assert_tracecnt(_cntstruct_, _uservarnumb_) 0
|
||||
#define if_assert_usertracker(_cntstruct_, _uservarnumb_) if(0)
|
||||
#define tern_assert_usertracker(_cntstruct_, _uservarnumb_) 0
|
||||
#define TrackerGet_Ok(_cntstruct_) dummy
|
||||
#define TrackerGet_Err(_cntstruct_) dummy
|
||||
#define TrackerGet_Warn(_cntstruct_) dummy
|
||||
#define TrackerGet_User(_cntstruct_, _uservarnumb_) dummy
|
||||
#define TrackerCnt_Ok(_cntstruct_)
|
||||
#define TrackerCnt_Err(_cntstruct_)
|
||||
#define TrackerCnt_Warn(_cntstruct_)
|
||||
#define TrackerCnt_User(_cntstruct_, _uservarnumb_)
|
||||
#define TrackerWrite_User(_cntstruct_, _uservarnumb_, _val_)
|
||||
#define TrackerClear_All(_cntstruct_)
|
||||
#define TrackerClear_Ok(_cntstruct_)
|
||||
#define TrackerClear_Err(_cntstruct_)
|
||||
#define TrackerClear_Warn(_cntstruct_)
|
||||
#define TrackerClear_User(_cntstruct_)
|
||||
#define TrackerClear_UserAll(_cntstruct_)
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_TRACE_LIB
|
||||
#include "trace.h"
|
||||
#else
|
||||
#define my_printf(...)
|
||||
#define log_printf(TAG, fmt, ...)
|
||||
#define TRACE_GPIO_SET(_gpio_,_pin_)
|
||||
#define TRACE_GPIO_RESET(_gpio_,_pin_)
|
||||
#define RTT_FlashPrepare(...)
|
||||
#define RTT_EraseFlash(...) 0
|
||||
#define RTT_SaveToFlash(...) 0
|
||||
#define RTT_ReadFromFlash(...) 0
|
||||
#define HF_CheckRecovered(...) 0
|
||||
#define HF_HandleFault(...)
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_EVOLVE_OPTIMIZER
|
||||
#include "evolve_optimizer.h"
|
||||
#else
|
||||
typedef struct {
|
||||
uint16_t n_params;
|
||||
uint16_t n_cand;
|
||||
uint16_t n_best;
|
||||
uint16_t iq_mutation;
|
||||
int32_t loss[0];
|
||||
int32_t candidates[0][0];
|
||||
} EvolveOptimizer_t;
|
||||
#define EvolveOptimizer_Init(opt, n_params, n_cand, n_best, iq_mutation, start_params)
|
||||
#define EvolveOptimizer_Step(opt, params, LossFunc)
|
||||
#define PARAM_SCALE_Q16(x, min_val, max_val) (x)
|
||||
#define PARAM_UNSCALE_Q16(q16_val, min_val, max_val) (q16_val)
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_GENERAL_PERIPH_LIBS
|
||||
|
||||
#include "__general_flash.h"
|
||||
#include "general_gpio.h"
|
||||
#ifdef HAL_SPI_MODULE_ENABLED
|
||||
#include "general_spi.h"
|
||||
#endif
|
||||
#ifdef HAL_UART_MODULE_ENABLED
|
||||
#include "general_uart.h"
|
||||
#endif
|
||||
#ifdef HAL_TIM_MODULE_ENABLED
|
||||
#include "general_tim.h"
|
||||
#endif
|
||||
|
||||
#endif //INCLUDE_GENERAL_PERIPH_LIBS
|
||||
|
||||
|
||||
|
||||
|
||||
/////////////////////////---USER SETTINGS---/////////////////////////
|
||||
// user includes
|
||||
|
||||
// user settings
|
||||
/////////////////////////---USER SETTINGS---/////////////////////////
|
||||
|
||||
|
||||
#endif // __MYLIBS_INCLUDE_H_
|
||||
312
MyLibs/Inc/bench_time.h
Normal file
312
MyLibs/Inc/bench_time.h
Normal file
@@ -0,0 +1,312 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file bench_time.h
|
||||
* @brief Заголовочный файл для измерения времени между событиями
|
||||
******************************************************************************
|
||||
* @addtogroup BENCH_TIME Time measurement
|
||||
* @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 Измерение периода на указанном канале
|
||||
* @param channel Номер канала (0..BENCH_TIME_MAX_CHANNELS-1)
|
||||
* @param ticks Источник тиков (например: HAL_GetTick(), TIM2->CNT, DWT->CYCCNT)
|
||||
* @param tick_period Период тиков для переполнения
|
||||
* @return Измеренное время в тиках, 0 - в случае первого запуска или ошибки
|
||||
*/
|
||||
static inline uint32_t BenchTime_Period(uint8_t channel, uint32_t ticks, uint32_t tick_period) {
|
||||
if (channel >= BENCH_TIME_MAX_CHANNELS) return 0;
|
||||
if (!hbt.channels[channel].is_running)
|
||||
{
|
||||
hbt.channels[channel].start_tick = ticks;
|
||||
hbt.channels[channel].tick_period = tick_period;
|
||||
hbt.channels[channel].is_running = 1;
|
||||
return 0;
|
||||
};
|
||||
|
||||
uint32_t end_tick = ticks;
|
||||
uint32_t start_tick = hbt.channels[channel].start_tick;
|
||||
uint32_t elapsed_ticks;
|
||||
|
||||
// Инит для следующего измерения
|
||||
hbt.channels[channel].start_tick = end_tick;
|
||||
hbt.channels[channel].tick_period = tick_period;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Обновление статистики
|
||||
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
|
||||
* @}
|
||||
*/
|
||||
@@ -4,7 +4,7 @@
|
||||
* @brief Заголочный файл для дефайнов битового доступа.
|
||||
**************************************************************************
|
||||
* @defgroup BIT_ACCESS_DEFINES Bit access defines
|
||||
* @ingroup MYLIBS_DEFINES
|
||||
* @ingroup MYLIBS_TOOLS
|
||||
* @brief Макросы и typedef'ы для работы с битами в unsigned типах.
|
||||
* @details
|
||||
В этом файле определены макросы для получения значения конкретного бита^
|
||||
@@ -119,6 +119,15 @@ typedef union
|
||||
}uint64_BitTypeDef;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Получить n-й бит из любого числа
|
||||
* @param _uint8_ Переменная типа uint8_t
|
||||
* @param _bit_ Константный номер бита (0..7)
|
||||
* @return Значение выбранного бита (0 или 1)
|
||||
* @note Индекс бита вычисляется программно, а не на этапе компиляции
|
||||
*/
|
||||
#define read_bit(_val_, _bit_) ((_val_) & ((uint64_t)1 << _bit_))
|
||||
|
||||
/**
|
||||
* @brief Получить n-й бит из uint8_t
|
||||
* @param _uint8_ Переменная типа uint8_t
|
||||
@@ -156,4 +165,4 @@ typedef union
|
||||
|
||||
/** BIT_ACCESS_DEFINES
|
||||
* @}
|
||||
*/
|
||||
*/
|
||||
|
||||
531
MyLibs/Inc/filters.h
Normal file
531
MyLibs/Inc/filters.h
Normal file
@@ -0,0 +1,531 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file filters.h
|
||||
* @brief Заголовочный файл библиотеки фильтров
|
||||
******************************************************************************
|
||||
* @addtogroup FILTERS Filters Library
|
||||
* @brief Библиотека математических фильтров и коррекций
|
||||
* @details
|
||||
Поддерживает:
|
||||
- Медианную фильтрацию (float и int32_t)
|
||||
- Экспоненциальное скользящее среднее (float и int32_t)
|
||||
- Скользящее среднее арифметическое (float и int32_t)
|
||||
- Полиномиальную коррекцию (float и int32_t)
|
||||
- Табличный фильтр LUT (Look-Up Table) (float и int32_t)
|
||||
|
||||
Параметры для конфигурации:
|
||||
- @ref FILTERS_ENABLE - Включить библиотеку фильтров
|
||||
- @ref FILTER_MEDIAN_MAX_SIZE - Размер окна медианного фильтра (по умолчанию 5)
|
||||
- @ref FILTER_AVERAGE_MAX_SIZE - Размер окна усредняющего фильтра (по умолчанию 8)
|
||||
- @ref FILTER_POLY_MAX_ORDER - Максимальный порядок полинома (по умолчанию 4)
|
||||
|
||||
@par Пример использования:
|
||||
@code
|
||||
#include "filters.h"
|
||||
|
||||
// Фильтры для float
|
||||
FilterMedian_t median_f;
|
||||
FilterExp_t exp_f;
|
||||
FilterAverage_t avg_f;
|
||||
FilterPoly_t poly_f;
|
||||
|
||||
// Фильтры для int32_t
|
||||
FilterMedianInt_t median_i;
|
||||
FilterExpInt_t exp_i;
|
||||
FilterAverageInt_t avg_i;
|
||||
FilterPolyInt_t poly_i;
|
||||
|
||||
// Коэффициенты полинома
|
||||
float poly_coeffs[3] = {0.0f, 1.1f, -0.05f};
|
||||
int32_t poly_coeffs_int[3] = {0, 110, -5}; // 1.1 и -0.05 с масштабом 100
|
||||
|
||||
void filters_init(void) {
|
||||
// Float версии
|
||||
FilterMedian_Init(&median_f);
|
||||
FilterExp_Init(&exp_f, 0.1f);
|
||||
FilterAverage_Init(&avg_f);
|
||||
FilterPoly_Init(&poly_f, poly_coeffs, 3);
|
||||
|
||||
// Int версии
|
||||
FilterMedianInt_Init(&median_i);
|
||||
FilterExpInt_Init(&exp_i, 10); // alpha = 0.1 с масштабом 100
|
||||
FilterAverageInt_Init(&avg_i);
|
||||
FilterPolyInt_Init(&poly_i, poly_coeffs_int, 3, 100); // масштаб 100
|
||||
}
|
||||
|
||||
// Обработка float значений
|
||||
float process_value_float(float raw) {
|
||||
float filtered;
|
||||
filtered = FilterMedian_Process(&median_f, raw);
|
||||
filtered = FilterExp_Process(&exp_f, filtered);
|
||||
filtered = FilterAverage_Process(&avg_f, filtered);
|
||||
filtered = FilterPoly_Process(&poly_f, filtered);
|
||||
return filtered;
|
||||
}
|
||||
|
||||
// Обработка int32_t значений (квантов АЦП)
|
||||
int32_t process_value_int(int32_t raw_adc_quant) {
|
||||
int32_t filtered;
|
||||
filtered = FilterMedianInt_Process(&median_i, raw_adc_quant);
|
||||
filtered = FilterExpInt_Process(&exp_i, filtered);
|
||||
filtered = FilterAverageInt_Process(&avg_i, filtered);
|
||||
filtered = FilterPolyInt_Process(&poly_i, filtered);
|
||||
return filtered;
|
||||
}
|
||||
@endcode
|
||||
* @{
|
||||
*****************************************************************************/
|
||||
#ifndef __FILTERS_H_
|
||||
#define __FILTERS_H_
|
||||
#include "mylibs_defs.h"
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef FILTERS_ENABLE
|
||||
|
||||
#ifdef ARM_MATH_CM4
|
||||
#include "arm_math.h"
|
||||
#define DSP_FITLERS 1
|
||||
#else
|
||||
#include "math.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef FILTER_AVERAGE_MAX_SIZE
|
||||
#ifndef FILTERS_DISABLE_MOVING_AVERAGE
|
||||
#define FILTER_AVERAGE_MAX_SIZE 100 ///< Размер окна усредняющего фильтра
|
||||
#else
|
||||
#define FILTER_AVERAGE_MAX_SIZE 65535 ///< Размер окна усредняющего фильтра без буфера
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef FILTER_MEDIAN_MAX_SIZE
|
||||
#define FILTER_MEDIAN_MAX_SIZE 10 ///< Размер окна медианного фильтра
|
||||
#endif
|
||||
|
||||
#ifndef FILTER_POLY_MAX_ORDER
|
||||
#define FILTER_POLY_MAX_ORDER 4 ///< Максимальный порядок полинома
|
||||
#endif
|
||||
|
||||
#ifndef FILTER_RMS_MAX_SIZE
|
||||
#define FILTER_RMS_MAX_SIZE 128 ///< Максимальный размер окна (рекомендуется степень 2)
|
||||
#endif
|
||||
|
||||
#define check_proccess_func(_ptr_) \
|
||||
((_fltr_)->process != NULL) 1 : \
|
||||
((_fltr_)->process == &FilterMedian_Init) 0 : \
|
||||
((_fltr_)->process == &FilterExp_Init) 0 : \
|
||||
((_fltr_)->process == &FilterAverage_Init) 0 : \
|
||||
((_fltr_)->process == &FilterPoly_Init) 0 : \
|
||||
((_fltr_)->process == &FilterLUT_Init) 0 : 1
|
||||
|
||||
|
||||
#define check_init_func(_ptr_) \
|
||||
((_fltr_)->process != NULL) 1 : \
|
||||
((_fltr_)->process == &FilterMedian_Process) 0 : \
|
||||
((_fltr_)->process == &FilterExp_Process) 0 : \
|
||||
((_fltr_)->process == &FilterExp_Process) 0 : \
|
||||
((_fltr_)->process == &FilterPoly_Process) 0 : \
|
||||
((_fltr_)->process == &FilterLUT_Process) 0 : 1
|
||||
|
||||
/**
|
||||
* @brief Сброс фильтра (повторная инициализация)
|
||||
* @param filter Указатель на структуру фильтра
|
||||
* @details Запускает функцию инициализации, если указатель инициализирован
|
||||
*/
|
||||
#define Filter_ReInit(_fltr_, ...) \
|
||||
((_fltr_)->reset != NULL) ? (_fltr_)->reset(_fltr_, __VA_ARGS__): -1
|
||||
|
||||
|
||||
/**
|
||||
* @brief Обработать число фильтром
|
||||
* @param filter Указатель на структуру фильтра
|
||||
* @details Запускает функцию фильтрации, если указатель инициализирован
|
||||
*/
|
||||
#define Filter_Process(_fltr_, _input_) \
|
||||
((_fltr_)->process != NULL) ? (_fltr_)->process(_fltr_, _input_): 0
|
||||
|
||||
/**
|
||||
* @brief Запуск фильтра
|
||||
* @param filter Указатель на структуру фильтра
|
||||
* @details Запускает фильтр только если он в состоянии готовности.
|
||||
* Если он не инициализирован или уже запущен - ничего не делается
|
||||
*/
|
||||
#define Filter_Start(_fltr_) \
|
||||
do{ if(Filter_isReady(_fltr_)) (_fltr_)->state = FILTER_ENABLE; }while(0)
|
||||
|
||||
/**
|
||||
* @brief Остановка работы фильтра
|
||||
* @param filter Указатель на структуру фильтра
|
||||
* @details Останавливет фильтр только если он запущен @ref Filter_Start.
|
||||
* Если он не инициализирован или уже остановлен - ничего не делается
|
||||
*/
|
||||
#define Filter_Stop(_fltr_) \
|
||||
do{ if(Filter_isEnable(_fltr_)) (_fltr_)->state = FILTER_READY; }while(0)
|
||||
|
||||
#define Filter_isDataReady(_fltr_) ((_fltr_)->dataProcessing == 0)
|
||||
|
||||
#define Filter_GetState(_fltr_) (_fltr_)->state
|
||||
#define Filter_isInit(_fltr_) !(Filter_GetState(_fltr_) == FILTER_NOT_INIT)
|
||||
#define Filter_isReady(_fltr_) (Filter_GetState(_fltr_) == FILTER_READY)
|
||||
#define Filter_isEnable(_fltr_) (Filter_GetState(_fltr_) == FILTER_ENABLE)
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FILTER_NOT_INIT,
|
||||
FILTER_READY,
|
||||
FILTER_ENABLE
|
||||
}FilterState_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FILTER_MODE_DEFAULT = 0,
|
||||
FILTER_MODE_MOVING,
|
||||
} FilterMode_t;
|
||||
|
||||
|
||||
// ==================== FLOAT ВЕРСИИ ====================
|
||||
|
||||
/**
|
||||
* @brief Структура медианного фильтра (float)
|
||||
*/
|
||||
typedef struct _FilterMedian_t{
|
||||
FilterState_t state; ///< Состояние фильтра
|
||||
float buffer[FILTER_MEDIAN_MAX_SIZE]; ///< Буфер значений
|
||||
uint8_t index; ///< Текущий индекс
|
||||
uint8_t size; ///< Фактический размер фильтра
|
||||
uint8_t dataProcessing; ///< Флаг - данные в обработке
|
||||
|
||||
int (*reset)(struct _FilterMedian_t *filter, uint8_t size, float init_val);
|
||||
float (*process)(struct _FilterMedian_t *filter, float input);
|
||||
} FilterMedian_t;
|
||||
|
||||
/**
|
||||
* @brief Структура экспоненциального фильтра (float)
|
||||
*/
|
||||
typedef struct _FilterExp_t {
|
||||
FilterState_t state; ///< Состояние фильтра
|
||||
float alpha; ///< Коэффициент сглаживания (0..1)
|
||||
float value; ///< Текущее значение
|
||||
uint8_t initialized; ///< Флаг инициализации
|
||||
uint8_t dataProcessing; ///< Флаг - данные в обработке
|
||||
|
||||
int (*reset)(struct _FilterExp_t *filter, float alpha);
|
||||
float (*process)(struct _FilterExp_t *filter, float input);
|
||||
} FilterExp_t;
|
||||
|
||||
/**
|
||||
* @brief Структура фильтра скользящего среднего (float)
|
||||
*/
|
||||
typedef struct _FilterAverage_t{
|
||||
FilterState_t state; ///< Состояние фильтра
|
||||
FilterMode_t mode; ///< Режим фильтра
|
||||
#ifndef FILTERS_DISABLE_MOVING_AVERAGE
|
||||
float buffer[FILTER_AVERAGE_MAX_SIZE]; ///< Буфер значений
|
||||
#endif
|
||||
uint32_t size; ///< Фактический размер фильтра
|
||||
float sum; ///< Сумма значений
|
||||
uint32_t index; ///< Текущий индекс
|
||||
uint32_t count; ///< Количество элементов
|
||||
float lastValue; ///< Последнее измеренное значение
|
||||
uint8_t dataProcessing; ///< Флаг - данные в обработке
|
||||
|
||||
int (*reset)(struct _FilterAverage_t *filter, uint32_t size, FilterMode_t mode);
|
||||
float (*process)(struct _FilterAverage_t *filter, float input);
|
||||
} FilterAverage_t;
|
||||
|
||||
/**
|
||||
* @brief Структура полиномиальной коррекции (float)
|
||||
*/
|
||||
typedef struct _FilterPoly_t{
|
||||
FilterState_t state; ///< Состояние фильтра
|
||||
float coefficients[FILTER_POLY_MAX_ORDER + 1]; ///< Коэффициенты полинома
|
||||
uint8_t order; ///< Порядок полинома
|
||||
uint8_t dataProcessing; ///< Флаг - данные в обработке
|
||||
|
||||
int (*reset)(struct _FilterPoly_t *filter, float* coeffs, uint8_t order);
|
||||
float (*process)(struct _FilterPoly_t *filter, float input);
|
||||
} FilterPoly_t;
|
||||
|
||||
/**
|
||||
* @brief Структура табличного фильтра (float)
|
||||
*/
|
||||
typedef struct _FilterLUT_t{
|
||||
FilterState_t state; ///< Состояние фильтра
|
||||
float* input_values; // Массив входных значений
|
||||
float* output_values; // Массив выходных значений
|
||||
float offset; // Смещение input_values
|
||||
uint16_t size; // Размер таблицы
|
||||
uint8_t interpolation; // Флаг интерполяции (0 - отключена, 1 - линейная)
|
||||
uint8_t dataProcessing; ///< Флаг - данные в обработке
|
||||
|
||||
int (*reset)(struct _FilterLUT_t *filter, float* input_arr, float* output_arr, uint16_t size, uint8_t interpolation, float offset);
|
||||
float (*process)(struct _FilterLUT_t *filter, float input);
|
||||
} FilterLUT_t;
|
||||
|
||||
/**
|
||||
* @brief Структура True RMS фильтра (float)
|
||||
*/
|
||||
typedef struct _FilterRMS_t {
|
||||
FilterState_t state; ///< Состояние фильтра
|
||||
float buffer_sq[FILTER_RMS_MAX_SIZE]; ///< Буфер квадратов значений
|
||||
float sum_squares; ///< Текущая сумма квадратов
|
||||
float last_rms; ///< Последнее рассчитанное RMS значение
|
||||
uint32_t window_size; ///< Размер окна усреднения
|
||||
uint32_t index; ///< Текущий индекс в буфере
|
||||
uint32_t count; ///< Количество накопленных значений
|
||||
uint8_t dataProcessing; ///< Флаг - данные в обработке
|
||||
|
||||
int (*reset)(struct _FilterRMS_t *filter, uint32_t window_size);
|
||||
float (*process)(struct _FilterRMS_t *filter, float input);
|
||||
} FilterRMS_t;
|
||||
|
||||
// Float версии функций
|
||||
int FilterMedian_Init(FilterMedian_t* filter, uint8_t size, float init_val);
|
||||
float FilterMedian_Process(FilterMedian_t* filter, float input);
|
||||
int FilterExp_Init(FilterExp_t* filter, float alpha);
|
||||
float FilterExp_Process(FilterExp_t* filter, float input);
|
||||
int FilterAverage_Init(FilterAverage_t* filter, uint32_t size, FilterMode_t mode);
|
||||
float FilterAverage_Process(FilterAverage_t* filter, float input);
|
||||
int FilterPoly_Init(FilterPoly_t* filter, float* coeffs, uint8_t order);
|
||||
float FilterPoly_Process(FilterPoly_t* filter, float input);
|
||||
int FilterLUT_Init(FilterLUT_t* filter, float* input_arr, float* output_arr, uint16_t size, uint8_t interpolation, float offset);
|
||||
float FilterLUT_Process(FilterLUT_t* filter, float input);
|
||||
int FilterRMS_Init(FilterRMS_t* filter, uint32_t window_size);
|
||||
float FilterRMS_Process(FilterRMS_t* filter, float input);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Расчет коэфициента альфа
|
||||
* @param tau Постоянная времени (время нарастания до 63% от уровня сигнала)
|
||||
* @param TsUs Период вызова фильтра в микросекундах
|
||||
* @return Коэфициент альфа
|
||||
*/
|
||||
#define FilterExp_CalcAlpha(tau, TsUs) (((float)TsUs/1000000) / (((float)TsUs/1000000) + (tau)))
|
||||
|
||||
/**
|
||||
* @brief Расчет alpha для времени нарастания до 63%
|
||||
* @param rise_time Требуемое время нарастания до 63%
|
||||
* @param TsUs Период вызова фильтра в микросекундах
|
||||
* @return Коэфициент альфа
|
||||
*/
|
||||
#define FilterExp_CalcAlpha63(rise_time, TsUs) FilterExp_CalcAlpha((rise_time) / 1.0f, TsUs)
|
||||
|
||||
/**
|
||||
* @brief Расчет alpha для времени нарастания до 86%
|
||||
* @param rise_time Требуемое время нарастания до 86%
|
||||
* @param TsUs Период вызова фильтра в микросекундах
|
||||
* @return Коэфициент альфа
|
||||
*/
|
||||
#define FilterExp_CalcAlpha86(rise_time, TsUs) FilterExp_CalcAlpha((rise_time) / 2.0f, TsUs)
|
||||
|
||||
/**
|
||||
* @brief Расчет alpha для времени нарастания до 95%
|
||||
* @param rise_time Требуемое время нарастания до 95%
|
||||
* @param TsUs Период вызова фильтра в микросекундах
|
||||
* @return Коэфициент альфа
|
||||
*/
|
||||
#define FilterExp_CalcAlpha95(rise_time, TsUs) FilterExp_CalcAlpha((rise_time) / 3.0f, TsUs)
|
||||
|
||||
/**
|
||||
* @brief Расчет alpha для времени нарастания до 98%
|
||||
* @param rise_time Требуемое время нарастания до 98%
|
||||
* @param TsUs Период вызова фильтра в микросекундах
|
||||
* @return Коэфициент альфа
|
||||
*/
|
||||
#define FilterExp_CalcAlpha98(rise_time, TsUs) FilterExp_CalcAlpha((rise_time) / 4.0f, TsUs)
|
||||
|
||||
/**
|
||||
* @brief Расчет alpha для времени нарастания до 99%
|
||||
* @param rise_time Требуемое время нарастания до 99%
|
||||
* @param TsUs Период вызова фильтра в микросекундах
|
||||
* @return Коэфициент альфа
|
||||
*/
|
||||
#define FilterExp_CalcAlpha99(rise_time, TsUs) FilterExp_CalcAlpha((rise_time) / 5.0f, TsUs)
|
||||
// ==================== INT32_T ВЕРСИИ ====================
|
||||
|
||||
/**
|
||||
* @brief Структура медианного фильтра (int32_t)
|
||||
*/
|
||||
typedef struct _FilterMedianInt_t{
|
||||
FilterState_t state; ///< Состояние фильтра
|
||||
int32_t buffer[FILTER_MEDIAN_MAX_SIZE]; ///< Буфер значений
|
||||
int32_t sorted[FILTER_MEDIAN_MAX_SIZE]; ///< Буфер отсортированных значений
|
||||
uint8_t index; ///< Текущий индекс
|
||||
uint8_t size; ///< Фактический размер фильтра
|
||||
uint8_t dataProcessing; ///< Флаг - данные в обработке
|
||||
|
||||
int (*reset)(struct _FilterMedianInt_t *filter, uint8_t size, int32_t init_val);
|
||||
int32_t (*process)(struct _FilterMedianInt_t *filter, int32_t input);
|
||||
} FilterMedianInt_t;
|
||||
|
||||
/**
|
||||
* @brief Структура экспоненциального фильтра (int32_t)
|
||||
*/
|
||||
typedef struct _FilterExpInt_t{
|
||||
FilterState_t state; ///< Состояние фильтра
|
||||
int32_t alpha; ///< Коэффициент сглаживания (в масштабе scale)
|
||||
int32_t value; ///< Текущее значение
|
||||
uint8_t initialized; ///< Флаг инициализации
|
||||
int32_t scale; ///< Масштаб коэффициента (например 100 для 0.01)
|
||||
uint8_t dataProcessing; ///< Флаг - данные в обработке
|
||||
|
||||
int (*reset)(struct _FilterExpInt_t *filter, int32_t alpha, int32_t scale);
|
||||
int32_t (*process)(struct _FilterExpInt_t *filter, int32_t input);
|
||||
} FilterExpInt_t;
|
||||
|
||||
/**
|
||||
* @brief Структура фильтра скользящего среднего (int32_t)
|
||||
*/
|
||||
typedef struct _FilterAverageInt_t{
|
||||
FilterState_t state; ///< Состояние фильтра
|
||||
FilterMode_t mode; ///< Режим фильтра
|
||||
#ifndef FILTERS_DISABLE_MOVING_AVERAGE
|
||||
int32_t buffer[FILTER_AVERAGE_MAX_SIZE]; ///< Буфер значений
|
||||
#endif
|
||||
uint32_t size; ///< Фактический размер фильтра
|
||||
int64_t sum; ///< Сумма значений
|
||||
uint32_t index; ///< Текущий индекс
|
||||
uint32_t count; ///< Количество элементов
|
||||
uint32_t lastValue; ///< Последнее измеренное значение
|
||||
uint8_t dataProcessing; ///< Флаг - данные в обработке
|
||||
|
||||
int (*reset)(struct _FilterAverageInt_t *filter, uint32_t size, FilterMode_t mode);
|
||||
int32_t (*process)(struct _FilterAverageInt_t *filter, int32_t input);
|
||||
} FilterAverageInt_t;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Структура полиномиальной коррекции (int32_t)
|
||||
*/
|
||||
typedef struct _FilterPolyInt_t{
|
||||
FilterState_t state; ///< Состояние фильтра
|
||||
int32_t coefficients[FILTER_POLY_MAX_ORDER + 1]; ///< Коэффициенты полинома
|
||||
uint8_t order; ///< Порядок полинома
|
||||
int32_t scale; ///< Масштаб коэффициентов
|
||||
uint8_t dataProcessing; ///< Флаг - данные в обработке
|
||||
|
||||
int (*reset)(struct _FilterPolyInt_t *filter, int32_t* coeffs, uint8_t order, int32_t scale);
|
||||
int32_t (*process)(struct _FilterPolyInt_t *filter, int32_t input);
|
||||
} FilterPolyInt_t;
|
||||
|
||||
/**
|
||||
* @brief Структура табличного фильтра (int32_t)
|
||||
*/
|
||||
typedef struct _FilterLUTInt_t{
|
||||
FilterState_t state; ///< Состояние фильтра
|
||||
int32_t* input_values; ///< Массив входных значений
|
||||
int32_t* output_values; ///< Массив выходных значений
|
||||
uint16_t size; ///< Размер таблицы
|
||||
uint8_t interpolation; ///< Флаг интерполяции
|
||||
uint8_t dataProcessing; ///< Флаг - данные в обработке
|
||||
|
||||
int (*reset)(struct _FilterLUTInt_t *filter, int32_t* input_arr, int32_t* output_arr, uint16_t size, uint8_t interpolation);
|
||||
int32_t (*process)(struct _FilterLUTInt_t *filter, int32_t input);
|
||||
} FilterLUTInt_t;
|
||||
|
||||
/**
|
||||
* @brief Структура True RMS фильтра (int32_t)
|
||||
*/
|
||||
typedef struct _FilterRMSInt_t {
|
||||
FilterState_t state; ///< Состояние фильтра
|
||||
int64_t buffer_sq[FILTER_RMS_MAX_SIZE]; ///< Буфер квадратов значений
|
||||
int64_t sum_squares; ///< Текущая сумма квадратов
|
||||
int32_t last_rms; ///< Последнее рассчитанное RMS значение
|
||||
uint32_t window_size; ///< Размер окна усреднения
|
||||
uint32_t index; ///< Текущий индекс в буфере
|
||||
uint32_t count; ///< Количество накопленных значений
|
||||
uint8_t dataProcessing; ///< Флаг - данные в обработке
|
||||
|
||||
int (*reset)(struct _FilterRMSInt_t *filter, uint32_t window_size);
|
||||
int32_t (*process)(struct _FilterRMSInt_t *filter, int32_t input);
|
||||
} FilterRMSInt_t;
|
||||
|
||||
// Int32_t версии функций
|
||||
int FilterMedianInt_Init(FilterMedianInt_t* filter, uint8_t size, int32_t init_val);
|
||||
int32_t FilterMedianInt_Process(FilterMedianInt_t* filter, int32_t input);
|
||||
int FilterExpInt_Init(FilterExpInt_t* filter, int32_t alpha, int32_t scale);
|
||||
int32_t FilterExpInt_Process(FilterExpInt_t* filter, int32_t input);
|
||||
int FilterAverageInt_Init(FilterAverageInt_t* filter, uint32_t size, FilterMode_t mode);
|
||||
int32_t FilterAverageInt_Process(FilterAverageInt_t* filter, int32_t input);
|
||||
int FilterPolyInt_Init(FilterPolyInt_t* filter, int32_t* coeffs, uint8_t order, int32_t scale);
|
||||
int32_t FilterPolyInt_Process(FilterPolyInt_t* filter, int32_t input);
|
||||
int FilterLUTInt_Init(FilterLUTInt_t* filter, int32_t* input_arr, int32_t* output_arr, uint16_t size, uint8_t interpolation);
|
||||
int32_t FilterLUTInt_Process(FilterLUTInt_t* filter, int32_t input);
|
||||
int FilterRMSInt_Init(FilterRMSInt_t* filter, uint32_t window_size);
|
||||
int32_t FilterRMSInt_Process(FilterRMSInt_t* filter, int32_t input);
|
||||
|
||||
|
||||
|
||||
// ==================== ДРУГИЕ ФИЛЬТРЫ ====================
|
||||
|
||||
|
||||
/**
|
||||
* @brief Структура полосового фильтра с дифференциатором
|
||||
* @details Комбинация дифференциатора и полосового фильтра 2-го порядка.
|
||||
* Используется для выделения сетевой частоты и подготовки к детектированию нуля.
|
||||
*/
|
||||
typedef struct _FilterBandPass_t {
|
||||
FilterState_t state; ///< Состояние фильтра
|
||||
|
||||
// Дифференциатор
|
||||
float prev_input; ///< Предыдущее входное значение
|
||||
|
||||
// Полосовой фильтр (биквадратный, прямая форма II)
|
||||
float b0, b1, b2; ///< Коэффициенты числителя
|
||||
float a1, a2; ///< Коэффициенты знаменателя
|
||||
|
||||
// Состояния фильтра
|
||||
float x1, x2; ///< Состояния входа
|
||||
float y1, y2; ///< Состояния выхода
|
||||
|
||||
float last_output; ///< Последнее выходное значение
|
||||
uint8_t dataProcessing; ///< Флаг обработки данных
|
||||
|
||||
// Указатели на функции
|
||||
int (*reset)(struct _FilterBandPass_t *filter,
|
||||
float center_freq_ratio, float bandwidth_ratio);
|
||||
float (*process)(struct _FilterBandPass_t *filter, float input);
|
||||
} FilterBandPass_t;
|
||||
|
||||
int FilterBandPass_Init(FilterBandPass_t* filter,
|
||||
float center_freq_ratio,
|
||||
float bandwidth_ratio);
|
||||
int FilterBandPass_CalcPhaseDegTable(FilterBandPass_t* filter,
|
||||
float* phase_table,
|
||||
const float* freq_points,
|
||||
int num_points);
|
||||
float FilterBandPass_Process(FilterBandPass_t* filter,
|
||||
float input);
|
||||
|
||||
#ifdef DSP_FITLERS
|
||||
/**
|
||||
* @brief Структура биквадратного фильтра с CMSIS-DSP
|
||||
*/
|
||||
typedef struct _FilterBiquad_t{
|
||||
FilterState_t state; ///< Состояние фильтра
|
||||
arm_biquad_cascade_df2T_instance_f32 instance; ///< CMSIS-DSP instance
|
||||
float32_t coeffs[5]; ///< Коэффициенты [b0, b1, b2, a1, a2]
|
||||
float32_t state_buffer[4]; ///< Буфер состояний (2 состояния на каскад)
|
||||
|
||||
int (*reset)(struct _FilterBiquad_t *filter, const float32_t coeffs[5]);
|
||||
float (*process)(struct _FilterBiquad_t *filter, float input);
|
||||
} FilterBiquad_t;
|
||||
|
||||
|
||||
// CMSIS версии функций
|
||||
int FilterBiquad_Init(FilterBiquad_t* filter, const float32_t coeffs[5]);
|
||||
float FilterBiquad_Process(FilterBiquad_t* filter, float input);
|
||||
#endif //DSP_FITLERS
|
||||
|
||||
|
||||
|
||||
|
||||
#else // FILTERS_ENABLE
|
||||
|
||||
#endif // FILTERS_ENABLE
|
||||
|
||||
#endif // __FILTERS_H_
|
||||
@@ -1,10 +1,9 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file evolve_optimizer.h
|
||||
* @file gen_optimizer.h
|
||||
* @brief Заголовочный файл для адаптивного подбора параметров
|
||||
******************************************************************************
|
||||
* @addtogroup EVOLVE_OPTIMIZER Evolve optimizer
|
||||
* @ingroup MYLIBS_DEFINES
|
||||
* @addtogroup GEN_OPTIMIZER Genetic optimizer
|
||||
* @brief Библиотека для эволюционного подбора параметров
|
||||
* @details
|
||||
Поддерживает:
|
||||
@@ -15,24 +14,24 @@
|
||||
|
||||
|
||||
Параметры для конфигурации:
|
||||
- @ref ENABLE_EVOLVE_OPTIMIZATION - Включить оптимизацию параметров
|
||||
Если библиотека отключена @ref ENABLE_EVOLVE_OPTIMIZATION, то вставляются
|
||||
- @ref GEN_OPTIMIZATION_ENABLE - Включить оптимизацию параметров
|
||||
Если библиотека отключена @ref GEN_OPTIMIZATION_ENABLE, то вставляются
|
||||
заглушки, никак не влияющие на параметры и остальную программу
|
||||
- @ref EVOLVE_MAX_PARAMS - Максимальное количество параметров
|
||||
- @ref EVOLVE_MAX_CANDIDATES - Максимальное количество кандидатов для обучения
|
||||
- (опционально) @ref EVOLVE_MUTATION_MIN_PCT - Минимальная мутация в процентах от Loss (по умолчанию 10%)
|
||||
- (опционально) @ref EVOLVE_MUTATION_MAX_PCT - Максимальная мутация в процентах от Loss (по умолчанию 100%)
|
||||
- @ref GEN_MAX_PARAMS - Максимальное количество параметров
|
||||
- @ref GEN_MAX_CANDIDATES - Максимальное количество кандидатов для обучения
|
||||
- (опционально) @ref GEN_MUTATION_MIN_PCT - Минимальная мутация в процентах от Loss (по умолчанию 10%)
|
||||
- (опционально) @ref GEN_MUTATION_MAX_PCT - Максимальная мутация в процентах от Loss (по умолчанию 100%)
|
||||
- (опционально) @ref ELOVLE_N_ELITE_CANDIDATE - Количество кандидатов, которые проходят в поколение без изменений
|
||||
|
||||
@par Пример использования:
|
||||
@code
|
||||
#include "evolve_optimizer.h"
|
||||
#include "gen_optimizer.h"
|
||||
#define N_PARAMS 4
|
||||
#define N_CANDIDATES 100
|
||||
#define N_BEST 10
|
||||
#define MUTATION 0.1f
|
||||
float params[N_PARAMS];
|
||||
EvolveOptimizer_t optimizer;
|
||||
GenOptimizer_t optimizer;
|
||||
|
||||
// Формирование параметров
|
||||
uint16_t param_u16 = 800;
|
||||
@@ -45,11 +44,11 @@ params[2] = PARAM_SCALE(param_u8, 10.0f, 100.0f);
|
||||
params[3] = PARAM_SCALE(param_i16, 500.0f, 5000.0f);
|
||||
|
||||
// Инициалиазция
|
||||
EvolveOptimizer_Init(&optimizer, N_PARAMS, N_CANDIDATES, N_BEST, MUTATION, params);
|
||||
GenOptimizer_Init(&optimizer, N_PARAMS, N_CANDIDATES, N_BEST, MUTATION, params);
|
||||
|
||||
// Шаг эволюции
|
||||
float loss = calc_loss(); // расчет эффективности параметров (от 0 до 1)
|
||||
EvolveOptimizer_Step(&optimizer, params, loss);
|
||||
GenOptimizer_Step(&optimizer, params, loss);
|
||||
|
||||
// Взятие следующих для эволюции параметров
|
||||
param_u16 = PARAM_UNSCALE(params[0], 0.0f, 1000.0f);
|
||||
@@ -59,14 +58,14 @@ param_i16 = PARAM_UNSCALE(params[3], 500.0f, 5000.0f);
|
||||
@endcode
|
||||
* @{
|
||||
*****************************************************************************/
|
||||
#ifndef __EVOLVE_OPTIMIZER_H_
|
||||
#define __EVOLVE_OPTIMIZER_H_
|
||||
#ifndef __GEN_OPTIMIZER_H_
|
||||
#define __GEN_OPTIMIZER_H_
|
||||
|
||||
#include "mylibs_defs.h"
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef ENABLE_EVOLVE_OPTIMIZATION
|
||||
#ifdef GEN_OPTIMIZATION_ENABLE
|
||||
/**
|
||||
* @brief Линейное масштабирование x из диапазона [min_val, max_val] в диапазон [0, 1)
|
||||
*/
|
||||
@@ -85,11 +84,11 @@ param_i16 = PARAM_UNSCALE(params[3], 500.0f, 5000.0f);
|
||||
|
||||
|
||||
|
||||
#ifndef EVOLVE_MUTATION_MIN_PCT
|
||||
#define EVOLVE_MUTATION_MIN_PCT 10 ///< Минимальная мутация (в процентах от Loss)
|
||||
#ifndef GEN_MUTATION_MIN_PCT
|
||||
#define GEN_MUTATION_MIN_PCT 10 ///< Минимальная мутация (в процентах от Loss)
|
||||
#endif
|
||||
#ifndef EVOLVE_MUTATION_MAX_PCT
|
||||
#define EVOLVE_MUTATION_MAX_PCT 100 ///< Максимальная мутация (в процентах от Loss)
|
||||
#ifndef GEN_MUTATION_MAX_PCT
|
||||
#define GEN_MUTATION_MAX_PCT 100 ///< Максимальная мутация (в процентах от Loss)
|
||||
#endif
|
||||
#ifndef ELOVLE_N_ELITE_CANDIDATE
|
||||
#define ELOVLE_N_ELITE_CANDIDATE 2 ///< Количество кандидатов, которые проходят в поколение без изменений (по умолчанию 2)
|
||||
@@ -107,25 +106,25 @@ typedef struct {
|
||||
uint16_t n_best; ///< Количество лучших, усредняемых
|
||||
float mutation_amp; ///< Амплитуда мутации (0..1)
|
||||
|
||||
uint16_t cand_index; ///< Индекс кандидата для обработки
|
||||
uint16_t cand_index; ///< Индекс текущего кандидата
|
||||
uint16_t gen_index; ///< Индекс популяции
|
||||
|
||||
//INTERNAL
|
||||
float gen_mut; ///< Амплитуда мутации у текущей популяции
|
||||
|
||||
float loss[EVOLVE_MAX_CANDIDATES]; ///< Loss для каждого кандидата
|
||||
float candidates[EVOLVE_MAX_CANDIDATES][EVOLVE_MAX_PARAMS]; ///< Параметры кандидатов
|
||||
uint16_t sorted_idx[EVOLVE_MAX_CANDIDATES]; ///< Индексы отсортированных кандидатов
|
||||
} EvolveOptimizer_t;
|
||||
float loss[GEN_MAX_CANDIDATES]; ///< Loss для каждого кандидата
|
||||
float candidates[GEN_MAX_CANDIDATES][GEN_MAX_PARAMS]; ///< Параметры кандидатов
|
||||
uint16_t sorted_idx[GEN_MAX_CANDIDATES]; ///< Индексы отсортированных кандидатов
|
||||
} GenOptimizer_t;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @cond EVOLVE_INTERNAL
|
||||
* @cond GEN_INTERNAL
|
||||
*/
|
||||
|
||||
// Вспомогательный указатель для сортировки
|
||||
static EvolveOptimizer_t *g_sort_opt; // глобальный указатель на текущий оптимизатор
|
||||
static GenOptimizer_t *g_sort_opt; // глобальный указатель на текущий оптимизатор
|
||||
|
||||
// функция условия сортировки
|
||||
static int cmp_idx(const void *a, const void *b) {
|
||||
@@ -152,7 +151,7 @@ static int cmp_idx(const void *a, const void *b) {
|
||||
* @return 0 — если окей,
|
||||
* -1 — если ошибка
|
||||
*/
|
||||
__STATIC_INLINE int EvolveOptimizer_Init(EvolveOptimizer_t* opt,
|
||||
static int GenOptimizer_Init(GenOptimizer_t* opt,
|
||||
uint16_t n_params,
|
||||
uint16_t n_cand,
|
||||
uint16_t n_best,
|
||||
@@ -162,15 +161,15 @@ __STATIC_INLINE int EvolveOptimizer_Init(EvolveOptimizer_t* opt,
|
||||
if((opt == NULL) || (start_params == NULL))
|
||||
return -1;
|
||||
|
||||
if(n_params > EVOLVE_MAX_PARAMS)
|
||||
if(n_params > GEN_MAX_PARAMS)
|
||||
return -1;
|
||||
opt->n_params = n_params;
|
||||
|
||||
if(n_cand > EVOLVE_MAX_CANDIDATES)
|
||||
if(n_cand > GEN_MAX_CANDIDATES)
|
||||
return -1;
|
||||
opt->n_cand = n_cand;
|
||||
|
||||
if(n_best > EVOLVE_MAX_CANDIDATES/2)
|
||||
if(n_best > GEN_MAX_CANDIDATES/2)
|
||||
return -1;
|
||||
opt->n_best = n_best;
|
||||
|
||||
@@ -222,7 +221,7 @@ __STATIC_INLINE int EvolveOptimizer_Init(EvolveOptimizer_t* opt,
|
||||
* @note Функция использует глобальную внутреннюю переменную для сортировки.
|
||||
* Надо убедится что только один экземпляр функции запущен в момент времени
|
||||
*/
|
||||
__STATIC_INLINE int EvolveOptimizer_Step(EvolveOptimizer_t* opt,
|
||||
static int GenOptimizer_Step(GenOptimizer_t* opt,
|
||||
float* params,
|
||||
float loss)
|
||||
{
|
||||
@@ -230,15 +229,15 @@ __STATIC_INLINE int EvolveOptimizer_Step(EvolveOptimizer_t* opt,
|
||||
return -1;
|
||||
|
||||
uint16_t n_params = opt->n_params;
|
||||
if(n_params > EVOLVE_MAX_PARAMS)
|
||||
if(n_params > GEN_MAX_PARAMS)
|
||||
return -1;
|
||||
|
||||
uint16_t n_cand = opt->n_cand;
|
||||
if(n_cand > EVOLVE_MAX_CANDIDATES)
|
||||
if(n_cand > GEN_MAX_CANDIDATES)
|
||||
return -1;
|
||||
|
||||
uint16_t n_best = opt->n_best;
|
||||
if(n_best > EVOLVE_MAX_CANDIDATES/2)
|
||||
if(n_best > GEN_MAX_CANDIDATES/2)
|
||||
return -1;
|
||||
|
||||
float mut = opt->mutation_amp;
|
||||
@@ -280,8 +279,8 @@ __STATIC_INLINE int EvolveOptimizer_Step(EvolveOptimizer_t* opt,
|
||||
if(opt->stability < 0.0f) opt->stability = 0.0f;
|
||||
if(opt->stability > 1.0f) opt->stability = 1.0f;
|
||||
|
||||
float mut_pct = EVOLVE_MUTATION_MIN_PCT +
|
||||
(EVOLVE_MUTATION_MAX_PCT - EVOLVE_MUTATION_MIN_PCT) * loss_ratio;
|
||||
float mut_pct = GEN_MUTATION_MIN_PCT +
|
||||
(GEN_MUTATION_MAX_PCT - GEN_MUTATION_MIN_PCT) * loss_ratio;
|
||||
float adaptive_mut = mut * (mut_pct / 100.0f);
|
||||
if (adaptive_mut < 0.0001f) adaptive_mut = 0.0001f;
|
||||
opt->gen_mut = adaptive_mut;
|
||||
@@ -315,7 +314,7 @@ __STATIC_INLINE int EvolveOptimizer_Step(EvolveOptimizer_t* opt,
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else // ENABLE_EVOLVE_OPTIMIZATION
|
||||
#else // GEN_OPTIMIZATION_ENABLE
|
||||
//заглушки
|
||||
typedef struct {
|
||||
uint16_t n_params;
|
||||
@@ -324,15 +323,15 @@ typedef struct {
|
||||
float mutation_amp;
|
||||
float loss[0];
|
||||
float candidates[0][0];
|
||||
} EvolveOptimizer_t;
|
||||
#define EvolveOptimizer_Init(opt, n_params, n_cand, n_best, mutation_amp, start_params)
|
||||
#define EvolveOptimizer_Step(opt, params, LossFunc)
|
||||
} GenOptimizer_t;
|
||||
#define GenOptimizer_Init(opt, n_params, n_cand, n_best, mutation_amp, start_params)
|
||||
#define GenOptimizer_Step(opt, params, LossFunc)
|
||||
#define PARAM_SCALE(x, min_val, max_val) (x)
|
||||
#define PARAM_UNSCALE(val, min_val, max_val) (val)
|
||||
#endif // ENABLE_EVOLVE_OPTIMIZATION
|
||||
#endif // GEN_OPTIMIZATION_ENABLE
|
||||
|
||||
#endif // __EVOLVE_OPTIMIZER_H_
|
||||
#endif // __GEN_OPTIMIZER_H_
|
||||
|
||||
/** EVOLVE_OPTIMIZER
|
||||
/** GEN_OPTIMIZER
|
||||
* @}
|
||||
*/
|
||||
@@ -3,13 +3,28 @@
|
||||
* @file mylibs_defs.h
|
||||
* @brief Заголочный файл для дефайнов библиотеки MyLibsGeneral.
|
||||
**************************************************************************
|
||||
* @defgroup MYLIBS_DEFINES General Tools
|
||||
* @defgroup MYLIBS_TOOLS General Tools
|
||||
* @ingroup MYLIBS_ALL
|
||||
* @brief Общие макросы и typedef'ы, используемые по всему проекту
|
||||
*
|
||||
* @defgroup MYLIBS_DEBUG_TOOLS Debug Tools
|
||||
* @ingroup MYLIBS_ALL
|
||||
* @brief Утилиты для тестирования программы
|
||||
*
|
||||
* @addtogroup BENCH_TIME
|
||||
* @ingroup MYLIBS_DEBUG_TOOLS
|
||||
*
|
||||
* @addtogroup GEN_OPTIMIZER
|
||||
* @ingroup MYLIBS_DEBUG_TOOLS
|
||||
*
|
||||
* @addtogroup TRACE
|
||||
* @ingroup MYLIBS_DEBUG_TOOLS
|
||||
*
|
||||
* @addtogroup TRACKERS
|
||||
* @ingroup MYLIBS_DEBUG_TOOLS
|
||||
*************************************************************************/
|
||||
#ifndef __MYLIBS_DEFINES_H_
|
||||
#define __MYLIBS_DEFINES_H_
|
||||
#ifndef __MYLIBS_TOOLS_H_
|
||||
#define __MYLIBS_TOOLS_H_
|
||||
|
||||
#include "mylibs_config.h"
|
||||
|
||||
@@ -17,7 +32,7 @@
|
||||
******************************ERROR_HANDLER********************************/
|
||||
/**
|
||||
* @addtogroup ERROR_HANDLER_DEFINES Error Handler defines
|
||||
* @ingroup MYLIBS_DEFINES
|
||||
* @ingroup MYLIBS_TOOLS
|
||||
* @brief Дефайны для обработки ошибок
|
||||
* @{
|
||||
*/
|
||||
@@ -58,14 +73,14 @@ extern void Error_Handler(void);
|
||||
******************************DELAYS_DEFINES*******************************/
|
||||
/**
|
||||
* @addtogroup DELAYS_DEFINES Delays defines
|
||||
* @ingroup MYLIBS_DEFINES
|
||||
* @ingroup MYLIBS_TOOLS
|
||||
* @brief Макросы и определения для работы с задержками в миллисекундах.
|
||||
* @details
|
||||
* Этот блок содержит макросы для реализации задержек с использованием HAL или FreeRTOS:
|
||||
* - @ref msDelay — простая задержка заданной длительности;
|
||||
* - @ref msDelayStart — сохранение текущего времени начала задержки;
|
||||
* - @ref msDelayWhileActive — проверка, активна ли задержка;
|
||||
* - @ref msDelayWaitDone — проверка, завершена ли задержка.
|
||||
* - @ref msDelayActive — проверка, активна ли задержка;
|
||||
* - @ref msDelayDone — проверка, завершена ли задержка.
|
||||
* Эти макросы удобны для реализации неблокирующих задержек.
|
||||
* @{
|
||||
*/
|
||||
@@ -77,13 +92,18 @@ extern void Error_Handler(void);
|
||||
* @note Использует задержку через @ref local_time или osDelay в зависимости от @ref FREERTOS_DELAY.
|
||||
*/
|
||||
#ifdef FREERTOS_DELAY
|
||||
#define msDelay(_ms_) osDelay(_ms_)
|
||||
__STATIC_INLINE void msDelay(uint32_t _ms_)
|
||||
{
|
||||
osDelay(_ms_);
|
||||
}
|
||||
#else
|
||||
#define msDelay(_ms_) \
|
||||
do { \
|
||||
uint32_t _start_ = local_time(); \
|
||||
while (local_time() - _start_ < (_ms_)) {} \
|
||||
} while(0)
|
||||
__STATIC_INLINE void msDelay(uint32_t _ms_)
|
||||
{
|
||||
volatile uint32_t _start_ = local_time();
|
||||
while ((local_time() - _start_) < (_ms_))
|
||||
{
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -95,7 +115,10 @@ extern void Error_Handler(void);
|
||||
*
|
||||
* Используется для реализации неблокирующих задержек.
|
||||
*/
|
||||
#define msDelayStart(_pvar_) *(_pvar_) = local_time()
|
||||
__STATIC_INLINE void msDelayStart(uint32_t *_pvar_)
|
||||
{
|
||||
*(_pvar_) = local_time();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Проверяет, активна ли задержка.
|
||||
@@ -104,15 +127,18 @@ extern void Error_Handler(void);
|
||||
* @retval 1 Задержка еще активна.
|
||||
* @retval 0 Задержка завершена.
|
||||
* @details
|
||||
* Возвращает true, пока время задержки не истекло. Используется в проверках,
|
||||
* Возвращает true, пока задержка активна. Используется в проверках,
|
||||
* когда нужно **действовать, пока задержка выполняется**. Пример:
|
||||
* @code
|
||||
* while(msDelayWhileActive(1000, &tick)) {
|
||||
* while(msDelayActive(1000, &tick)) {
|
||||
* // выполняем другие задачи, задержка не блокирует поток
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
#define msDelayWhileActive(_ms_, _pvar_) (local_time() - *(_pvar_) < _ms_)
|
||||
__STATIC_INLINE int msDelayActive(uint32_t _ms_, uint32_t *_pvar_)
|
||||
{
|
||||
return (local_time() - *(_pvar_) < _ms_);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Проверяет, завершилась ли задержка.
|
||||
@@ -121,15 +147,18 @@ extern void Error_Handler(void);
|
||||
* @retval 1 Задержка завершена.
|
||||
* @retval 0 Задержка еще активна.
|
||||
* @details
|
||||
* Возвращает true, когда задержка уже завершена. Используется в проверках,
|
||||
* Возвращает true, когда задержка закончилась. Используется в проверках,
|
||||
* когда нужно **выполнить действие только после окончания задержки**. Пример:
|
||||
* @code
|
||||
* if(msDelayWaitDone(1000, &tick)) {
|
||||
* if(msDelayDone(1000, &tick)) {
|
||||
* // выполняем действие после завершения задержки
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
#define msDelayWaitDone(_ms_, _pvar_) (local_time() - *(_pvar_) >= _ms_)
|
||||
__STATIC_INLINE int msDelayDone(uint32_t _ms_, uint32_t *_pvar_)
|
||||
{
|
||||
return (local_time() - *(_pvar_) >= _ms_);
|
||||
}
|
||||
|
||||
/** DELAYS_DEFINES
|
||||
* @}
|
||||
@@ -138,14 +167,19 @@ extern void Error_Handler(void);
|
||||
|
||||
/***************************************************************************
|
||||
*******************************UTIL_DEFINES********************************/
|
||||
static int dummy;
|
||||
/**
|
||||
* @addtogroup UTILS_DEFINES Utils defines
|
||||
* @ingroup MYLIBS_DEFINES
|
||||
* @ingroup MYLIBS_TOOLS
|
||||
* @brief Общие вспомогательные макросы
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Размер структуры в её элементах.
|
||||
* @param _struct_ Структура, размер которой надо вычислить.
|
||||
*/
|
||||
#define numbof(_arr_) (sizeof(_arr_)/sizeof(_arr_[0]))
|
||||
|
||||
/**
|
||||
* @brief Обнуление структуры.
|
||||
* @param _struct_ Структура, которую нужно обнулить.
|
||||
@@ -181,6 +215,12 @@ static int dummy;
|
||||
*/
|
||||
#define ABS(x) ( ((x) > 0)? (x) : -(x))
|
||||
|
||||
/**
|
||||
* @brief Константа Пи
|
||||
*/
|
||||
#ifndef PI
|
||||
#define PI 3.14159265f
|
||||
#endif
|
||||
/** UTILS_DEFINES
|
||||
* @}
|
||||
*/
|
||||
@@ -191,6 +231,7 @@ static int dummy;
|
||||
* @cond LIBS_INTERNAL
|
||||
*/
|
||||
|
||||
static int dummy; // переменная которой присваиваются значения, которые некуда присвоить
|
||||
|
||||
/**
|
||||
* @brief Аналог HAL макроса для привязки DMA к UART.
|
||||
@@ -203,4 +244,4 @@ do{ \
|
||||
|
||||
|
||||
/** @endcond */
|
||||
#endif //__MYLIBS_DEFINES_H_
|
||||
#endif //__MYLIBS_TOOLS_H_
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
* @brief Заголочный файл для работы с трассировкой.
|
||||
**************************************************************************
|
||||
* @addtogroup TRACE Trace defines
|
||||
* @ingroup MYLIBS_DEFINES
|
||||
* @brief Дефайны для работы с трассировкой
|
||||
*************************************************************************/
|
||||
#ifndef __TRACE_H_
|
||||
@@ -588,4 +587,4 @@ __STATIC_FORCEINLINE void HF_HandleFault(void)
|
||||
|
||||
|
||||
|
||||
#endif //__TRACE_H_
|
||||
#endif //__TRACE_H_
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
* @brief Заголочный файл для работы с трекерами @ref TRACKERS.
|
||||
**************************************************************************
|
||||
* @addtogroup TRACKERS Trackers defines
|
||||
* @ingroup MYLIBS_DEFINES
|
||||
* @brief Дефайны для работы с трекерами
|
||||
* @details
|
||||
Есть дефайн для объявления структуры трекера: TrackerTypeDef(num_user_vars).
|
||||
@@ -160,4 +159,4 @@
|
||||
|
||||
#endif //TRACKERS_ENABLE
|
||||
|
||||
#endif //__TRACKERS_H_
|
||||
#endif //__TRACKERS_H_
|
||||
|
||||
968
MyLibs/Src/filters.c
Normal file
968
MyLibs/Src/filters.c
Normal file
@@ -0,0 +1,968 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file filters.c
|
||||
* @brief Реализация библиотеки фильтров
|
||||
******************************************************************************
|
||||
*/
|
||||
#include "filters.h"
|
||||
|
||||
#ifdef FILTERS_ENABLE
|
||||
|
||||
|
||||
#define check_init_filter(_filter_) \
|
||||
do{ if (filter == NULL) return -1; \
|
||||
filter->state = FILTER_NOT_INIT;}while(0);
|
||||
|
||||
#define check_process_filter(_filter_) \
|
||||
do{ if ((filter == NULL) || (filter->state != FILTER_ENABLE)) return input;}while(0);
|
||||
|
||||
// ==================== FLOAT ВЕРСИИ ====================
|
||||
|
||||
// Вспомогательная функция для сравнения float
|
||||
static int Filter_float_compare(const void *a, const void *b) {
|
||||
float fa = *(const float*)a;
|
||||
float fb = *(const float*)b;
|
||||
if (fa < fb) return -1;
|
||||
if (fa > fb) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Инициализация медианного фильтра (float)
|
||||
* @param filter Указатель на структуру фильтра
|
||||
* @return 0 - успех, -1 - ошибка
|
||||
*/
|
||||
int FilterMedian_Init(FilterMedian_t* filter, uint8_t size, float init_val) {
|
||||
check_init_filter(filter);
|
||||
if (size == 0 || size > FILTER_MEDIAN_MAX_SIZE) return -1;
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
filter->buffer[i] = init_val;
|
||||
}
|
||||
filter->index = 0;
|
||||
filter->size = size;
|
||||
|
||||
filter->state = FILTER_READY;
|
||||
filter->reset = &FilterMedian_Init;
|
||||
filter->process = &FilterMedian_Process;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Обработка значения медианным фильтром (float)
|
||||
* @param filter Указатель на структуру фильтра
|
||||
* @param input Входное значение
|
||||
* @return Отфильтрованное значение
|
||||
*/
|
||||
float FilterMedian_Process(FilterMedian_t* filter, float input) {
|
||||
check_process_filter(filter);
|
||||
|
||||
// Добавляем значение в буфер
|
||||
filter->buffer[filter->index] = input;
|
||||
filter->index = (filter->index + 1) % filter->size;
|
||||
|
||||
// Копируем буфер для сортировки
|
||||
float sort_buffer[FILTER_MEDIAN_MAX_SIZE];
|
||||
memcpy(sort_buffer, filter->buffer, sizeof(sort_buffer));
|
||||
|
||||
// Сортируем и возвращаем медиану
|
||||
qsort(sort_buffer, filter->size, sizeof(float), Filter_float_compare);
|
||||
return sort_buffer[filter->size / 2];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Инициализация экспоненциального фильтра (float)
|
||||
* @param filter Указатель на структуру фильтра
|
||||
* @param alpha Коэффициент сглаживания (0..1)
|
||||
* @return 0 - успех, -1 - ошибка
|
||||
*/
|
||||
int FilterExp_Init(FilterExp_t* filter, float alpha) {
|
||||
check_init_filter(filter);
|
||||
|
||||
filter->alpha = alpha;
|
||||
filter->value = 0.0f;
|
||||
filter->initialized = 0;
|
||||
|
||||
filter->state = FILTER_READY;
|
||||
filter->reset = &FilterExp_Init;
|
||||
filter->process = &FilterExp_Process;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Обработка значения экспоненциальным фильтром (float)
|
||||
* @param filter Указатель на структуру фильтра
|
||||
* @param input Входное значение
|
||||
* @return Отфильтрованное значение
|
||||
*/
|
||||
float FilterExp_Process(FilterExp_t* filter, float input) {
|
||||
check_process_filter(filter);
|
||||
|
||||
if (!filter->initialized) {
|
||||
filter->value = input;
|
||||
filter->initialized = 1;
|
||||
return input;
|
||||
}
|
||||
|
||||
filter->value = filter->alpha * input + (1.0f - filter->alpha) * filter->value;
|
||||
return filter->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Инициализация фильтра скользящего среднего (float)
|
||||
* @param filter Указатель на структуру фильтра
|
||||
* @return 0 - успех, -1 - ошибка
|
||||
*/
|
||||
int FilterAverage_Init(FilterAverage_t* filter, uint32_t size, FilterMode_t mode) {
|
||||
check_init_filter(filter);
|
||||
if (size == 0 || size > FILTER_AVERAGE_MAX_SIZE) return -1;
|
||||
|
||||
#ifndef FILTERS_DISABLE_MOVING_AVERAGE
|
||||
memset(filter->buffer, 0, sizeof(filter->buffer));
|
||||
#endif
|
||||
filter->size = size;
|
||||
filter->sum = 0.0f;
|
||||
filter->index = 0;
|
||||
filter->count = 0;
|
||||
filter->mode = mode;
|
||||
|
||||
filter->state = FILTER_READY;
|
||||
filter->reset = &FilterAverage_Init;
|
||||
filter->process = &FilterAverage_Process;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Обработка значения фильтром скользящего среднего (float)
|
||||
* @param filter Указатель на структуру фильтра
|
||||
* @param input Входное значение
|
||||
* @return Отфильтрованное значение
|
||||
*/
|
||||
float FilterAverage_Process(FilterAverage_t* filter, float input) {
|
||||
check_process_filter(filter);
|
||||
|
||||
// Общая логика для обоих режимов
|
||||
filter->sum += input;
|
||||
filter->count++;
|
||||
filter->dataProcessing = 1;
|
||||
// Логика скользящего среднего
|
||||
if (filter->mode == FILTER_MODE_MOVING) {
|
||||
#ifndef FILTERS_DISABLE_MOVING_AVERAGE
|
||||
if (filter->count > filter->size) {
|
||||
filter->sum -= filter->buffer[filter->index];
|
||||
filter->count = filter->size; // Поддерживаем фиксированный размер окна
|
||||
}
|
||||
filter->buffer[filter->index] = input;
|
||||
filter->index = (filter->index + 1) % filter->size;
|
||||
filter->lastValue = filter->sum / filter->count;
|
||||
filter->dataProcessing = 0;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
if (filter->count >= filter->size)
|
||||
{
|
||||
filter->lastValue = filter->sum / filter->count;
|
||||
filter->count = 0;
|
||||
filter->sum = 0;
|
||||
filter->dataProcessing = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return filter->lastValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Инициализация полиномиальной коррекции (float)
|
||||
* @param filter Указатель на структуру коррекции
|
||||
* @param coeffs Массив коэффициентов полинома
|
||||
* @param order Порядок полинома
|
||||
* @return 0 - успех, -1 - ошибка
|
||||
*/
|
||||
int FilterPoly_Init(FilterPoly_t* filter, float* coeffs, uint8_t order) {
|
||||
check_init_filter(filter);
|
||||
if ((coeffs == NULL) || (order > FILTER_POLY_MAX_ORDER)) return -1;
|
||||
|
||||
filter->order = order;
|
||||
memcpy(filter->coefficients, coeffs, (order + 1) * sizeof(float));
|
||||
|
||||
filter->state = FILTER_READY;
|
||||
filter->reset = &FilterPoly_Init;
|
||||
filter->process = &FilterPoly_Process;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Применение полиномиальной коррекции к значению (float)
|
||||
* @param filter Указатель на структуру коррекции
|
||||
* @param input Входное значение
|
||||
* @return Скорректированное значение
|
||||
*/
|
||||
float FilterPoly_Process(FilterPoly_t* filter, float input) {
|
||||
check_process_filter(filter);
|
||||
|
||||
float result = 0.0f;
|
||||
float x_power = 1.0f;
|
||||
|
||||
for (uint8_t i = 0; i <= filter->order; i++) {
|
||||
result += filter->coefficients[i] * x_power;
|
||||
x_power *= input;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Инициализация табличного фильтра (float)
|
||||
* @param filter Указатель на структуру фильтра
|
||||
* @param input_arr Массив входных значений (должен быть отсортирован по возрастанию)
|
||||
* @param output_arr Массив выходных значений
|
||||
* @param size Размер таблицы
|
||||
* @param interpolation Флаг интерполяции (0 - ближайшее значение, 1 - линейная интерполяция)
|
||||
* @param offset Сдвиг input_arr для удобной коррекции
|
||||
* @return 0 - успех, -1 - ошибка
|
||||
*/
|
||||
int FilterLUT_Init(FilterLUT_t* filter, float* input_arr, float* output_arr, uint16_t size, uint8_t interpolation, float offset) {
|
||||
check_init_filter(filter);
|
||||
if ((input_arr == NULL) || (output_arr == NULL)) return -1;
|
||||
|
||||
filter->input_values = input_arr;
|
||||
filter->output_values = output_arr;
|
||||
filter->size = size;
|
||||
filter->interpolation = interpolation;
|
||||
filter->offset = offset;
|
||||
|
||||
filter->state = FILTER_READY;
|
||||
filter->reset = &FilterLUT_Init;
|
||||
filter->process = &FilterLUT_Process;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Обработка значения табличным фильтром (float)
|
||||
* @param filter Указатель на структуру фильтра
|
||||
* @param input Входное значение
|
||||
* @return Выходное значение по таблице
|
||||
*/
|
||||
float FilterLUT_Process(FilterLUT_t* filter, float input) {
|
||||
check_process_filter(filter);
|
||||
if((filter->input_values == NULL) || (filter->output_values == NULL)) {
|
||||
return input;
|
||||
}
|
||||
|
||||
// Поиск ближайших значений в таблице
|
||||
uint16_t left_index = 0;
|
||||
uint16_t right_index = filter->size - 1;
|
||||
|
||||
input -= filter->offset;
|
||||
// Если значение за пределами таблицы - возвращаем крайние значения
|
||||
if (input <= filter->input_values[0]) {
|
||||
return filter->output_values[0];
|
||||
}
|
||||
if (input >= filter->input_values[right_index]) {
|
||||
return filter->output_values[right_index];
|
||||
}
|
||||
|
||||
// Бинарный поиск позиции
|
||||
while (right_index - left_index > 1) {
|
||||
uint16_t mid_index = left_index + (right_index - left_index) / 2;
|
||||
if (input <= filter->input_values[mid_index]) {
|
||||
right_index = mid_index;
|
||||
} else {
|
||||
left_index = mid_index;
|
||||
}
|
||||
}
|
||||
|
||||
// Без интерполяции - возвращаем значение левой границы
|
||||
if (!filter->interpolation) {
|
||||
return filter->output_values[left_index];
|
||||
}
|
||||
|
||||
// Линейная интерполяция
|
||||
float x0 = filter->input_values[left_index];
|
||||
float x1 = filter->input_values[right_index];
|
||||
float y0 = filter->output_values[left_index];
|
||||
float y1 = filter->output_values[right_index];
|
||||
|
||||
if (x1 == x0) {
|
||||
return y0; // Избегаем деления на ноль
|
||||
}
|
||||
|
||||
return y0 + (input - x0) * (y1 - y0) / (x1 - x0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Инициализация RMS фильтра (float)
|
||||
*/
|
||||
int FilterRMS_Init(FilterRMS_t* filter, uint32_t window_size) {
|
||||
check_init_filter(filter);
|
||||
|
||||
if (window_size == 0 || window_size > FILTER_RMS_MAX_SIZE) return -1;
|
||||
|
||||
filter->window_size = window_size;
|
||||
filter->sum_squares = 0.0f;
|
||||
filter->last_rms = 0.0f;
|
||||
filter->index = 0;
|
||||
filter->count = 0;
|
||||
|
||||
// Инициализируем буфер нулями
|
||||
memset(filter->buffer_sq, 0, sizeof(filter->buffer_sq[0]) * window_size);
|
||||
|
||||
filter->state = FILTER_READY;
|
||||
filter->reset = &FilterRMS_Init;
|
||||
filter->process = &FilterRMS_Process;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Обработка значения RMS фильтром (float)
|
||||
* @details Эффективный алгоритм с циклическим буфером
|
||||
*/
|
||||
float FilterRMS_Process(FilterRMS_t* filter, float input) {
|
||||
check_process_filter(filter);
|
||||
|
||||
// Вычисляем квадрат входного значения
|
||||
float square = input * input;
|
||||
|
||||
if (filter->count < filter->window_size) {
|
||||
// Фаза накопления - просто добавляем в сумму
|
||||
filter->sum_squares += square;
|
||||
filter->buffer_sq[filter->index] = square;
|
||||
filter->count++;
|
||||
} else {
|
||||
// Фаза скользящего окна - вычитаем старое, добавляем новое
|
||||
filter->sum_squares -= filter->buffer_sq[filter->index]; // Вычитаем старое значение
|
||||
filter->sum_squares += square; // Добавляем новое
|
||||
filter->buffer_sq[filter->index] = square; // Сохраняем в буфер
|
||||
}
|
||||
|
||||
// Увеличиваем индекс с зацикливанием
|
||||
filter->index++;
|
||||
if (filter->index >= filter->window_size) {
|
||||
filter->index = 0;
|
||||
}
|
||||
|
||||
// Вычисляем RMS (проверяем что есть хотя бы одно значение)
|
||||
if (filter->count > 0) {
|
||||
float mean_square = filter->sum_squares / filter->count;
|
||||
// Защита от отрицательных значений из-за ошибок округления
|
||||
if (mean_square < 0.0f) mean_square = 0.0f;
|
||||
filter->last_rms = _sqrtf(mean_square);
|
||||
}
|
||||
|
||||
return filter->last_rms;
|
||||
}
|
||||
|
||||
|
||||
// ==================== INT32_T ВЕРСИИ ====================
|
||||
|
||||
//// Вспомогательная функция для сравнения int32_t
|
||||
//static int Filter_int32_compare(const void *a, const void *b) {
|
||||
// int32_t ia = *(const int32_t*)a;
|
||||
// int32_t ib = *(const int32_t*)b;
|
||||
// if (ia < ib) return -1;
|
||||
// if (ia > ib) return 1;
|
||||
// return 0;
|
||||
//}
|
||||
|
||||
/**
|
||||
* @brief Инициализация медианного фильтра (int32_t)
|
||||
* @param filter Указатель на структуру фильтра
|
||||
* @return 0 - успех, -1 - ошибка
|
||||
*/
|
||||
int FilterMedianInt_Init(FilterMedianInt_t* filter, uint8_t size, int32_t init_val) {
|
||||
check_init_filter(filter);
|
||||
if (size == 0 || size > FILTER_MEDIAN_MAX_SIZE) return -1;
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
filter->buffer[i] = init_val;
|
||||
filter->sorted[i] = init_val;
|
||||
}
|
||||
|
||||
filter->index = 0;
|
||||
filter->size = size;
|
||||
|
||||
filter->state = FILTER_READY;
|
||||
filter->reset = &FilterMedianInt_Init;
|
||||
filter->process = &FilterMedianInt_Process;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Обработка значения медианным фильтром (int32_t)
|
||||
* @param filter Указатель на структуру фильтра
|
||||
* @param input Входное значение
|
||||
* @return Отфильтрованное значение
|
||||
*/
|
||||
int32_t FilterMedianInt_Process(FilterMedianInt_t* filter, int32_t input) {
|
||||
check_process_filter(filter);
|
||||
|
||||
register int32_t old_value = filter->buffer[filter->index];
|
||||
register uint8_t size = filter->size;
|
||||
register uint8_t idx = filter->index;
|
||||
int32_t* sorted = filter->sorted;
|
||||
|
||||
// Обновляем circular buffer
|
||||
filter->buffer[idx] = input;
|
||||
idx++;
|
||||
if (idx >= size) idx = 0;
|
||||
filter->index = idx;
|
||||
|
||||
// Одновременно ищем позицию для удаления и вставки
|
||||
uint8_t remove_pos = 0;
|
||||
uint8_t insert_pos = 0;
|
||||
uint8_t found_remove = 0;
|
||||
|
||||
// Проход по массиву sorted (только один раз!)
|
||||
for (uint8_t i = 0; i < size; i++) {
|
||||
int32_t current = sorted[i];
|
||||
|
||||
// Ищем позицию для удаления старого значения
|
||||
if (!found_remove && current == old_value) {
|
||||
remove_pos = i;
|
||||
found_remove = 1;
|
||||
}
|
||||
|
||||
// Ищем позицию для вставки нового значения
|
||||
if (input > current) {
|
||||
insert_pos = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Если insert_pos указывает на место после удаляемого элемента,
|
||||
// нужно скорректировать, так как массив уменьшится на 1 элемент
|
||||
if (insert_pos > remove_pos) {
|
||||
insert_pos--;
|
||||
}
|
||||
|
||||
// Оптимизированное удаление и вставка за один проход
|
||||
if (insert_pos == remove_pos) {
|
||||
// Случай 1: Вставляем на то же место, откуда удаляем
|
||||
sorted[remove_pos] = input;
|
||||
}
|
||||
else if (insert_pos < remove_pos) {
|
||||
// Случай 2: Вставляем левее, чем удаляем
|
||||
// Сдвигаем элементы [insert_pos, remove_pos-1] вправо
|
||||
for (uint8_t j = remove_pos; j > insert_pos; j--) {
|
||||
sorted[j] = sorted[j - 1];
|
||||
}
|
||||
sorted[insert_pos] = input;
|
||||
}
|
||||
else {
|
||||
// Случай 3: Вставляем правее, чем удаляем (insert_pos > remove_pos)
|
||||
// Сдвигаем элементы [remove_pos+1, insert_pos] влево
|
||||
for (uint8_t j = remove_pos; j < insert_pos; j++) {
|
||||
sorted[j] = sorted[j + 1];
|
||||
}
|
||||
sorted[insert_pos - 1] = input;
|
||||
}
|
||||
|
||||
return sorted[size >> 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Инициализация экспоненциального фильтра (int32_t)
|
||||
* @param filter Указатель на структуру фильтра
|
||||
* @param alpha Коэффициент сглаживания в масштабированном виде
|
||||
* @param scale Масштаб коэффициента (например 100 для работы с процентами)
|
||||
* @return 0 - успех, -1 - ошибка
|
||||
*/
|
||||
int FilterExpInt_Init(FilterExpInt_t* filter, int32_t alpha, int32_t scale) {
|
||||
check_init_filter(filter);
|
||||
|
||||
filter->alpha = alpha;
|
||||
filter->scale = scale;
|
||||
filter->value = 0;
|
||||
filter->initialized = 0;
|
||||
|
||||
filter->state = FILTER_READY;
|
||||
filter->reset = &FilterExpInt_Init;
|
||||
filter->process = &FilterExpInt_Process;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Обработка значения экспоненциальным фильтром (int32_t)
|
||||
* @param filter Указатель на структуру фильтра
|
||||
* @param input Входное значение
|
||||
* @return Отфильтрованное значение
|
||||
*/
|
||||
int32_t FilterExpInt_Process(FilterExpInt_t* filter, int32_t input) {
|
||||
check_process_filter(filter);
|
||||
|
||||
if (!filter->initialized) {
|
||||
filter->value = input;
|
||||
filter->initialized = 1;
|
||||
return input;
|
||||
}
|
||||
|
||||
// value = (alpha * input + (scale - alpha) * value) / scale
|
||||
int64_t result = (int64_t)filter->alpha * input +
|
||||
(int64_t)(filter->scale - filter->alpha) * filter->value;
|
||||
filter->value = (int32_t)(result / filter->scale);
|
||||
|
||||
return filter->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Инициализация фильтра скользящего среднего (int32_t)
|
||||
* @param filter Указатель на структуру фильтра
|
||||
* @return 0 - успех, -1 - ошибка
|
||||
*/
|
||||
int FilterAverageInt_Init(FilterAverageInt_t* filter, uint32_t size, FilterMode_t mode) {
|
||||
check_init_filter(filter);
|
||||
if (size == 0 || size > FILTER_AVERAGE_MAX_SIZE) return - 1;
|
||||
#ifndef FILTERS_DISABLE_MOVING_AVERAGE
|
||||
memset(filter->buffer, 0, sizeof(filter->buffer));
|
||||
#endif
|
||||
filter->size = size;
|
||||
filter->sum = 0;
|
||||
filter->index = 0;
|
||||
filter->count = 0;
|
||||
filter->mode = mode;
|
||||
|
||||
filter->state = FILTER_READY;
|
||||
filter->reset = &FilterAverageInt_Init;
|
||||
filter->process = &FilterAverageInt_Process;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Обработка значения фильтром скользящего среднего (int32_t)
|
||||
* @param filter Указатель на структуру фильтра
|
||||
* @param input Входное значение
|
||||
* @return Отфильтрованное значение
|
||||
*/
|
||||
int32_t FilterAverageInt_Process(FilterAverageInt_t* filter, int32_t input) {
|
||||
check_process_filter(filter);
|
||||
|
||||
// Общая логика для обоих режимов
|
||||
filter->sum += input;
|
||||
filter->count++;
|
||||
|
||||
// Логика скользящего среднего
|
||||
if (filter->mode == FILTER_MODE_MOVING) {
|
||||
#ifndef FILTERS_DISABLE_MOVING_AVERAGE
|
||||
if (filter->count > filter->size) {
|
||||
filter->sum -= filter->buffer[filter->index];
|
||||
filter->count = filter->size; // Поддерживаем фиксированный размер окна
|
||||
}
|
||||
filter->buffer[filter->index] = input;
|
||||
filter->index = (filter->index + 1) % filter->size;
|
||||
filter->lastValue = filter->sum / filter->count;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
if (filter->count >= filter->size)
|
||||
{
|
||||
filter->lastValue = filter->sum / filter->count;
|
||||
filter->count = 0;
|
||||
filter->sum = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return filter->lastValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Инициализация полиномиальной коррекции (int32_t)
|
||||
* @param filter Указатель на структуру коррекции
|
||||
* @param coeffs Массив коэффициентов полинома в масштабированном виде
|
||||
* @param order Порядок полинома
|
||||
* @param scale Масштаб коэффициентов
|
||||
* @return 0 - успех, -1 - ошибка
|
||||
*/
|
||||
int FilterPolyInt_Init(FilterPolyInt_t* filter, int32_t* coeffs, uint8_t order, int32_t scale) {
|
||||
check_init_filter(filter);
|
||||
if ((coeffs == NULL) || (order > FILTER_POLY_MAX_ORDER)) return -1;
|
||||
|
||||
filter->order = order;
|
||||
filter->scale = scale;
|
||||
memcpy(filter->coefficients, coeffs, (order + 1) * sizeof(int32_t));
|
||||
|
||||
filter->state = FILTER_READY;
|
||||
filter->reset = &FilterPolyInt_Init;
|
||||
filter->process = &FilterPolyInt_Process;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Применение полиномиальной коррекции к значению (int32_t)
|
||||
* @param filter Указатель на структуру коррекции
|
||||
* @param input Входное значение
|
||||
* @return Скорректированное значение
|
||||
*/
|
||||
int32_t FilterPolyInt_Process(FilterPolyInt_t* filter, int32_t input) {
|
||||
check_process_filter(filter);
|
||||
|
||||
// coefficients[0] = a_n * scale
|
||||
// coefficients[1] = a_{n-1} * scale
|
||||
// ...
|
||||
// coefficients[n] = a_0 * scale
|
||||
|
||||
int64_t result = filter->coefficients[0]; // Старший коэффициент
|
||||
int64_t x_scaled = input;
|
||||
|
||||
for (uint8_t i = 1; i <= filter->order; i++) {
|
||||
result = (result * x_scaled) / filter->scale + filter->coefficients[i];
|
||||
}
|
||||
|
||||
// Домножаем на scale для a_0
|
||||
result = (result * filter->scale);
|
||||
|
||||
return (int32_t)(result / filter->scale);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Инициализация табличного фильтра (int32_t)
|
||||
* @param filter Указатель на структуру фильтра
|
||||
* @param input_arr Массив входных значений (должен быть отсортирован по возрастанию)
|
||||
* @param output_arr Массив выходных значений
|
||||
* @param size Размер таблицы
|
||||
* @param interpolation Флаг интерполяции (0 - ближайшее значение, 1 - линейная интерполяция)
|
||||
* @return 0 - успех, -1 - ошибка
|
||||
*/
|
||||
int FilterLUTInt_Init(FilterLUTInt_t* filter, int32_t* input_arr, int32_t* output_arr, uint16_t size, uint8_t interpolation) {
|
||||
check_init_filter(filter);
|
||||
if ((input_arr == NULL) || (output_arr == NULL)) return -1;
|
||||
|
||||
filter->input_values = input_arr;
|
||||
filter->output_values = output_arr;
|
||||
filter->size = size;
|
||||
filter->interpolation = interpolation;
|
||||
|
||||
filter->state = FILTER_READY;
|
||||
filter->reset = &FilterLUTInt_Init;
|
||||
filter->process = &FilterLUTInt_Process;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Обработка значения табличным фильтром (int32_t)
|
||||
* @param filter Указатель на структуру фильтра
|
||||
* @param input Входное значение
|
||||
* @return Выходное значение по таблице
|
||||
*/
|
||||
int32_t FilterLUTInt_Process(FilterLUTInt_t* filter, int32_t input) {
|
||||
check_process_filter(filter);
|
||||
if((filter->input_values == NULL) || (filter->output_values == NULL)) {
|
||||
return input;
|
||||
}
|
||||
|
||||
// Поиск ближайших значений в таблице
|
||||
uint16_t left_index = 0;
|
||||
uint16_t right_index = filter->size - 1;
|
||||
|
||||
// Если значение за пределами таблицы - возвращаем крайние значения
|
||||
if (input <= filter->input_values[0]) {
|
||||
return filter->output_values[0];
|
||||
}
|
||||
if (input >= filter->input_values[right_index]) {
|
||||
return filter->output_values[right_index];
|
||||
}
|
||||
|
||||
// Бинарный поиск позиции
|
||||
while (right_index - left_index > 1) {
|
||||
uint16_t mid_index = left_index + (right_index - left_index) / 2;
|
||||
if (input <= filter->input_values[mid_index]) {
|
||||
right_index = mid_index;
|
||||
} else {
|
||||
left_index = mid_index;
|
||||
}
|
||||
}
|
||||
|
||||
// Без интерполяции - возвращаем значение левой границы
|
||||
if (!filter->interpolation) {
|
||||
return filter->output_values[left_index];
|
||||
}
|
||||
|
||||
// Линейная интерполяция (целочисленная)
|
||||
int64_t x0 = filter->input_values[left_index];
|
||||
int64_t x1 = filter->input_values[right_index];
|
||||
int64_t y0 = filter->output_values[left_index];
|
||||
int64_t y1 = filter->output_values[right_index];
|
||||
|
||||
if (x1 == x0) {
|
||||
return (int32_t)y0; // Избегаем деления на ноль
|
||||
}
|
||||
|
||||
int64_t result = y0 + (input - x0) * (y1 - y0) / (x1 - x0);
|
||||
return (int32_t)result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Инициализация RMS фильтра (int32_t)
|
||||
*/
|
||||
int FilterRMSInt_Init(FilterRMSInt_t* filter, uint32_t window_size) {
|
||||
check_init_filter(filter);
|
||||
|
||||
if (window_size == 0 || window_size > FILTER_RMS_MAX_SIZE) return -1;
|
||||
|
||||
filter->window_size = window_size;
|
||||
filter->sum_squares = 0;
|
||||
filter->last_rms = 0;
|
||||
filter->index = 0;
|
||||
filter->count = 0;
|
||||
|
||||
// Инициализируем буфер нулями
|
||||
memset(filter->buffer_sq, 0, sizeof(filter->buffer_sq[0]) * window_size);
|
||||
|
||||
filter->state = FILTER_READY;
|
||||
filter->reset = &FilterRMSInt_Init;
|
||||
filter->process = &FilterRMSInt_Process;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Обработка значения RMS фильтром (int32_t)
|
||||
*/
|
||||
int32_t FilterRMSInt_Process(FilterRMSInt_t* filter, int32_t input) {
|
||||
check_process_filter(filter);
|
||||
|
||||
// Вычисляем квадрат входного значения
|
||||
int64_t square = (int64_t)input * input;
|
||||
|
||||
if (filter->count < filter->window_size) {
|
||||
// Фаза накопления
|
||||
filter->sum_squares += square;
|
||||
filter->buffer_sq[filter->index] = square;
|
||||
filter->count++;
|
||||
} else {
|
||||
// Фаза скользящего окна
|
||||
filter->sum_squares -= filter->buffer_sq[filter->index]; // Вычитаем старое
|
||||
filter->sum_squares += square; // Добавляем новое
|
||||
filter->buffer_sq[filter->index] = square; // Сохраняем в буфер
|
||||
}
|
||||
|
||||
// Увеличиваем индекс с зацикливанием
|
||||
filter->index++;
|
||||
if (filter->index >= filter->window_size) {
|
||||
filter->index = 0;
|
||||
}
|
||||
|
||||
// Вычисляем RMS
|
||||
if (filter->count > 0) {
|
||||
int64_t mean_square = filter->sum_squares / filter->count;
|
||||
// Защита от отрицательных значений
|
||||
if (mean_square < 0) mean_square = 0;
|
||||
filter->last_rms = (int32_t)_sqrtf((float)mean_square);
|
||||
}
|
||||
|
||||
return filter->last_rms;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ==================== ДРУГИЕ ФИЛЬТРЫ ====================
|
||||
|
||||
/**
|
||||
* @brief Инициализация полосового фильтра с дифференциатором
|
||||
* @param filter Указатель на структуру фильтра
|
||||
* @param center_freq_ratio Отношение центральной частоты к частоте дискретизации (0..0.5)
|
||||
* Например: 50 Гц / 1000 Гц = 0.05
|
||||
* @param bandwidth_ratio Относительная ширина полосы (0..1)
|
||||
* Например: 0.1 = полоса 10% от центральной частоты
|
||||
* @return 0 - успех, -1 - ошибка
|
||||
*/
|
||||
int FilterBandPass_Init(FilterBandPass_t* filter,
|
||||
float center_freq_ratio,
|
||||
float bandwidth_ratio) {
|
||||
check_init_filter(filter);
|
||||
|
||||
// Проверка параметров
|
||||
if (center_freq_ratio <= 0.0f || center_freq_ratio >= 0.5f) return -1;
|
||||
if (bandwidth_ratio <= 0.0f || bandwidth_ratio > 1.0f) return -1;
|
||||
|
||||
// 1. Расчет параметров полосового фильтра
|
||||
float w0 = 2.0f * PI * center_freq_ratio; // Нормированная угловая частота
|
||||
float Q = 1.0f / bandwidth_ratio; // Добротность
|
||||
float alpha = sinf(w0) / (2.0f * Q);
|
||||
float cos_w0 = cosf(w0);
|
||||
|
||||
// Коэффициенты биквадратного полосового фильтра
|
||||
// H_bp(z) = (alpha - alpha*z^-2) / (1 + a1*z^-1 + a2*z^-2)
|
||||
float b0_bp = alpha;
|
||||
float b1_bp = 0.0f;
|
||||
float b2_bp = -alpha;
|
||||
float a0_bp = 1.0f + alpha;
|
||||
float a1_bp = -2.0f * cos_w0;
|
||||
float a2_bp = 1.0f - alpha;
|
||||
|
||||
// Нормализация (a0 = 1)
|
||||
filter->b0 = b0_bp / a0_bp;
|
||||
filter->b1 = b1_bp / a0_bp;
|
||||
filter->b2 = b2_bp / a0_bp;
|
||||
filter->a1 = a1_bp / a0_bp;
|
||||
filter->a2 = a2_bp / a0_bp;
|
||||
|
||||
// 2. Дифференциатор реализуется отдельно в process()
|
||||
filter->prev_input = 0.0f;
|
||||
|
||||
// 3. Инициализация состояний фильтра
|
||||
filter->x1 = 0.0f;
|
||||
filter->x2 = 0.0f;
|
||||
filter->y1 = 0.0f;
|
||||
filter->y2 = 0.0f;
|
||||
filter->last_output = 0.0f;
|
||||
filter->dataProcessing = 0;
|
||||
|
||||
filter->state = FILTER_READY;
|
||||
filter->reset = &FilterBandPass_Init;
|
||||
filter->process = &FilterBandPass_Process;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* @brief Расчет таблицы фазовых сдвигов в градусах
|
||||
* @param filter Указатель на фильтр
|
||||
* @param phase_table Указатель на массив для фаз (в градусах)
|
||||
* @param freq_points Указатель на массив частот (0..0.5)
|
||||
* @param num_points Количество точек
|
||||
* @return 0 - успех, -1 - ошибка
|
||||
*//**
|
||||
* @brief Расчет с повышенной точностью через double
|
||||
*/
|
||||
int FilterBandPass_CalcPhaseDegTable(FilterBandPass_t* filter,
|
||||
float* phase_table,
|
||||
const float* freq_points,
|
||||
int num_points) {
|
||||
|
||||
if (!filter || !phase_table || !freq_points || num_points <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Копируем коэффициенты в double для точности
|
||||
double b0 = (double)filter->b0;
|
||||
double b1 = (double)filter->b1;
|
||||
double b2 = (double)filter->b2;
|
||||
double a1 = (double)filter->a1;
|
||||
double a2 = (double)filter->a2;
|
||||
|
||||
for (int i = 0; i < num_points; i++) {
|
||||
double omega = 2.0 * PI * (double)freq_points[i];
|
||||
|
||||
double cos_w = cos(omega);
|
||||
double sin_w = sin(omega);
|
||||
double cos_2w = cos(2.0 * omega);
|
||||
double sin_2w = sin(2.0 * omega);
|
||||
|
||||
double num_real = b0 + b1 * cos_w + b2 * cos_2w;
|
||||
double num_imag = -b1 * sin_w - b2 * sin_2w;
|
||||
|
||||
double den_real = 1.0 + a1 * cos_w + a2 * cos_2w;
|
||||
double den_imag = -a1 * sin_w - a2 * sin_2w;
|
||||
|
||||
// Используем устойчивое деление
|
||||
double mag_sq = den_real * den_real + den_imag * den_imag;
|
||||
|
||||
if (mag_sq < 1e-30) { // Более строгий порог для double
|
||||
phase_table[i] = 0.0f;
|
||||
continue;
|
||||
}
|
||||
|
||||
double H_real = (num_real * den_real + num_imag * den_imag) / mag_sq;
|
||||
double H_imag = (num_imag * den_real - num_real * den_imag) / mag_sq;
|
||||
|
||||
double phase_rad = atan2(H_imag, H_real);
|
||||
double phase_deg = phase_rad * 180.0 / PI;
|
||||
|
||||
// Нормализация
|
||||
while (phase_deg > 180.0) phase_deg -= 360.0;
|
||||
while (phase_deg < -180.0) phase_deg += 360.0;
|
||||
|
||||
phase_table[i] = (float)phase_deg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Обработка значения фильтром
|
||||
* @param filter Указатель на структуру фильтра
|
||||
* @param input Входное значение в диапазоне [-1.0, 1.0]
|
||||
* @return Отфильтрованное значение
|
||||
*
|
||||
* @details Алгоритм:
|
||||
// * 1. Вычисление производной: diff = input - prev_input
|
||||
* 2. Полосовая фильтрация diff
|
||||
* 3. Обновление состояний
|
||||
*/
|
||||
float FilterBandPass_Process(FilterBandPass_t* filter,
|
||||
float input) {
|
||||
check_process_filter(filter);
|
||||
|
||||
// 1. Дифференциатор (разностный фильтр 1-го порядка)
|
||||
//float diff = input - filter->prev_input;
|
||||
//filter->prev_input = input;
|
||||
float diff = input;
|
||||
|
||||
// 2. Полосовой фильтр (биквадратный, прямая форма II)
|
||||
// y[n] = b0*x[n] + b1*x[n-1] + b2*x[n-2] - a1*y[n-1] - a2*y[n-2]
|
||||
float output = filter->b0 * diff +
|
||||
filter->b1 * filter->x1 +
|
||||
filter->b2 * filter->x2 -
|
||||
filter->a1 * filter->y1 -
|
||||
filter->a2 * filter->y2;
|
||||
|
||||
// 3. Обновление состояний
|
||||
filter->x2 = filter->x1; // x[n-2] = x[n-1]
|
||||
filter->x1 = diff; // x[n-1] = x[n]
|
||||
filter->y2 = filter->y1; // y[n-2] = y[n-1]
|
||||
filter->y1 = output; // y[n-1] = y[n]
|
||||
|
||||
filter->last_output = output;
|
||||
filter->dataProcessing = 0; // Данные обработаны
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
#ifdef DSP_FITLERS
|
||||
|
||||
/**
|
||||
* @brief Инициализация биквадратного фильтра с CMSIS-DSP
|
||||
*/
|
||||
int FilterBiquad_Init(FilterBiquad_t* filter, const float32_t coeffs[5])
|
||||
{
|
||||
check_init_filter(filter);
|
||||
|
||||
if (coeffs == NULL) return -1;
|
||||
|
||||
memcpy(filter->coeffs, coeffs, sizeof(filter->coeffs));
|
||||
memset(filter->state_buffer, 0, sizeof(filter->state_buffer));
|
||||
|
||||
// Инициализация CMSIS-DSP структуры (1 каскад)
|
||||
arm_biquad_cascade_df2T_init_f32(&filter->instance,
|
||||
1,
|
||||
filter->coeffs,
|
||||
filter->state_buffer);
|
||||
|
||||
filter->state = FILTER_READY;
|
||||
filter->reset = &FilterBiquad_Init;
|
||||
filter->process = &FilterBiquad_Process;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Обработка значения биквадратным фильтром CMSIS-DSP
|
||||
*/
|
||||
float FilterBiquad_Process(FilterBiquad_t* filter, float input)
|
||||
{
|
||||
check_process_filter(filter);
|
||||
|
||||
float32_t in_arr[1] = {input};
|
||||
float32_t out_arr[1];
|
||||
|
||||
arm_biquad_cascade_df2T_f32(&filter->instance, in_arr, out_arr, 1);
|
||||
|
||||
return out_arr[0];
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // FILTERS_ENABLE
|
||||
54
README.md
54
README.md
@@ -1,6 +1,22 @@
|
||||
# Инструкция по подключению релиза библиотеки `ExtendedLibs`
|
||||
# Обзор `ExtendedLibs`
|
||||
|
||||
Данный субмодуль подключается напрямую из Git и содержит набор вспомогательных библиотек для работы МК, в частности STM32 и SEGGER RTT.
|
||||
ExtendedLibs - это набор библиотек для удобной работы с STM32. Данный субмодуль подключается напрямую из Git и содержит набор вспомогательных библиотек для работы МК, в частности STM32 и SEGGER RTT.
|
||||
|
||||
## Основные возможности
|
||||
|
||||
|
||||
#### Общие утилиты MyLibs (@ref MYLIBS_TOOLS)
|
||||
- Макросы для задержек (@ref DELAYS_DEFINES)
|
||||
- Утилиты для работы с всяким (@ref UTILS_DEFINES)
|
||||
- Битовый доступ к регистрам через union (@ref BIT_ACCESS_DEFINES)
|
||||
|
||||
#### Отладка* (@ref MYLIBS_DEBUG_TOOLS)
|
||||
- Трассировка (@ref TRACE)
|
||||
- Измерение временных интервалов (@ref BENCH_TIME)
|
||||
- Генетический алгоритм для оптимизации параметров (@ref GEN_OPTIMIZER)
|
||||
- Трекеры для статистики и отладки (@ref TRACKERS)
|
||||
|
||||
_*Модули отладки независимы от MyLibs и могут быть использованы отдельно_
|
||||
|
||||
## Структура библиотеки
|
||||
|
||||
@@ -13,29 +29,17 @@ ProjectRoot/
|
||||
│ │ ├── __mylibs_config.h # Конфигурация библиотек
|
||||
│ │ ├── mylibs_defs.h # Общие определения и макросы
|
||||
│ │ ├── bit_access.h # Битовый доступ к регистрам
|
||||
│ │ ├── evolve_optimizer.h # Оптимизатор (генетический алгоритм)
|
||||
│ │ ├── gen_optimizer.h # Оптимизатор (генетический алгоритм)
|
||||
│ │ ├── trackers.h # Трекеры для отладки
|
||||
│ │ └── trace.h # Трассировка и логирование
|
||||
│ └── src/
|
||||
│
|
||||
├──RTT # Библиотека RTT
|
||||
│ ├── __SEGGER_RTT_Conf.h # Конфигурационный файл RTT
|
||||
│ ├── SEGGER_RTT.c # Основной модуль RTT
|
||||
│ ├── SEGGER_RTT.h # Основной заголовок RTT
|
||||
│ ├── SEGGER_RTT_ASM_ARMv7M.S # Ассемблерная оптимизация для ARMv7M
|
||||
│ └── SEGGER_RTT_printf.c # Реализация printf() через RTT
|
||||
│
|
||||
└── STM32_General # Работа с периферией STM32
|
||||
├── inc/
|
||||
│ ├── general_gpio.h # Работа с GPIO
|
||||
│ ├── general_spi.h # Работа с SPI
|
||||
│ ├── general_tim.h # Работа с таймерами
|
||||
│ └── general_uart.h # Работа с UART
|
||||
└── src/
|
||||
├── general_gpio.c # Реализация GPIO
|
||||
├── general_spi.c # Реализация SPI
|
||||
├── general_tim.c # Реализация TIM
|
||||
└── general_uart.c # Реализация UART
|
||||
└──RTT # Библиотека RTT
|
||||
├── __SEGGER_RTT_Conf.h # Конфигурационный файл RTT
|
||||
├── SEGGER_RTT.c # Основной модуль RTT
|
||||
├── SEGGER_RTT.h # Основной заголовок RTT
|
||||
├── SEGGER_RTT_ASM_ARMv7M.S # Ассемблерная оптимизация для ARMv7M
|
||||
└── SEGGER_RTT_printf.c # Реализация printf() через RTT
|
||||
```
|
||||
|
||||
## Инструкция по подключению
|
||||
@@ -75,10 +79,4 @@ ProjectRoot/
|
||||
|
||||
```bash
|
||||
git submodule update --remote
|
||||
```
|
||||
|
||||
## Документация
|
||||
|
||||
Библиотека `MyLibs` и `STM32_General` документирована в формате Doxygen. HTML документацию можно скачать [здесь](https://git.arktika.cyou/Razvalyaev/STM32_ExtendedLibs/archive/0.02.zip)
|
||||
|
||||
Библиотека `RTT` документирована в формате [страницы википедии](https://kb.segger.com/RTT) и просто комментариями в коде.
|
||||
```
|
||||
394
RTT/SEGGER_RTT_Syscalls_KEIL.c
Normal file
394
RTT/SEGGER_RTT_Syscalls_KEIL.c
Normal file
@@ -0,0 +1,394 @@
|
||||
/*********************************************************************
|
||||
* SEGGER Microcontroller GmbH *
|
||||
* The Embedded Experts *
|
||||
**********************************************************************
|
||||
* *
|
||||
* (c) 1995 - 2021 SEGGER Microcontroller GmbH *
|
||||
* *
|
||||
* www.segger.com Support: support@segger.com *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* SEGGER RTT * Real Time Transfer for embedded targets *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* SEGGER strongly recommends to not make any changes *
|
||||
* to or modify the source code of this software in order to stay *
|
||||
* compatible with the RTT protocol and J-Link. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or *
|
||||
* without modification, are permitted provided that the following *
|
||||
* condition is met: *
|
||||
* *
|
||||
* o Redistributions of source code must retain the above copyright *
|
||||
* notice, this condition and the following disclaimer. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
|
||||
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
|
||||
* DAMAGE. *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* RTT version: 7.54 *
|
||||
* *
|
||||
**********************************************************************
|
||||
|
||||
---------------------------END-OF-HEADER------------------------------
|
||||
File : RTT_Syscalls_KEIL.c
|
||||
Purpose : Retargeting module for KEIL MDK-CM3.
|
||||
Low-level functions for using printf() via RTT
|
||||
Revision: $Rev: 24316 $
|
||||
Notes : (1) https://wiki.segger.com/Keil_MDK-ARM#RTT_in_uVision
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
#if (defined __CC_ARM) || (defined __ARMCC_VERSION)
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <rt_sys.h>
|
||||
#include <rt_misc.h>
|
||||
|
||||
#include "SEGGER_RTT.h"
|
||||
/*********************************************************************
|
||||
*
|
||||
* #pragmas
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
#if __ARMCC_VERSION < 6000000
|
||||
#pragma import(__use_no_semihosting)
|
||||
#endif
|
||||
|
||||
#ifdef _MICROLIB
|
||||
#pragma import(__use_full_stdio)
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Defines non-configurable
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
/* Standard IO device handles - arbitrary, but any real file system handles must be
|
||||
less than 0x8000. */
|
||||
#define STDIN 0x8001 // Standard Input Stream
|
||||
#define STDOUT 0x8002 // Standard Output Stream
|
||||
#define STDERR 0x8003 // Standard Error Stream
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Public const
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
#if __ARMCC_VERSION < 5000000
|
||||
//const char __stdin_name[] = "STDIN";
|
||||
const char __stdout_name[] = "STDOUT";
|
||||
const char __stderr_name[] = "STDERR";
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Public code
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* _ttywrch
|
||||
*
|
||||
* Function description:
|
||||
* Outputs a character to the console
|
||||
*
|
||||
* Parameters:
|
||||
* c - character to output
|
||||
*
|
||||
*/
|
||||
void _ttywrch(int c) {
|
||||
fputc(c, stdout); // stdout
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* _sys_open
|
||||
*
|
||||
* Function description:
|
||||
* Opens the device/file in order to do read/write operations
|
||||
*
|
||||
* Parameters:
|
||||
* sName - sName of the device/file to open
|
||||
* OpenMode - This parameter is currently ignored
|
||||
*
|
||||
* Return value:
|
||||
* != 0 - Handle to the object to open, otherwise
|
||||
* == 0 -"device" is not handled by this module
|
||||
*
|
||||
*/
|
||||
FILEHANDLE _sys_open(const char * sName, int OpenMode) {
|
||||
(void)OpenMode;
|
||||
// Register standard Input Output devices.
|
||||
if (strcmp(sName, __stdout_name) == 0) {
|
||||
return (STDOUT);
|
||||
} else if (strcmp(sName, __stderr_name) == 0) {
|
||||
return (STDERR);
|
||||
} else
|
||||
return (0); // Not implemented
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* _sys_close
|
||||
*
|
||||
* Function description:
|
||||
* Closes the handle to the open device/file
|
||||
*
|
||||
* Parameters:
|
||||
* hFile - Handle to a file opened via _sys_open
|
||||
*
|
||||
* Return value:
|
||||
* 0 - device/file closed
|
||||
*
|
||||
*/
|
||||
int _sys_close(FILEHANDLE hFile) {
|
||||
(void)hFile;
|
||||
return 0; // Not implemented
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* _sys_write
|
||||
*
|
||||
* Function description:
|
||||
* Writes the data to an open handle.
|
||||
* Currently this function only outputs data to the console
|
||||
*
|
||||
* Parameters:
|
||||
* hFile - Handle to a file opened via _sys_open
|
||||
* pBuffer - Pointer to the data that shall be written
|
||||
* NumBytes - Number of bytes to write
|
||||
* Mode - The Mode that shall be used
|
||||
*
|
||||
* Return value:
|
||||
* Number of bytes *not* written to the file/device
|
||||
*
|
||||
*/
|
||||
int _sys_write(FILEHANDLE hFile, const unsigned char * pBuffer, unsigned NumBytes, int Mode) {
|
||||
int r = 0;
|
||||
|
||||
(void)Mode;
|
||||
if (hFile == STDOUT) {
|
||||
SEGGER_RTT_Write(0, (const char*)pBuffer, NumBytes);
|
||||
return 0;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* _sys_read
|
||||
*
|
||||
* Function description:
|
||||
* Reads data from an open handle.
|
||||
* Currently this modules does nothing.
|
||||
*
|
||||
* Parameters:
|
||||
* hFile - Handle to a file opened via _sys_open
|
||||
* pBuffer - Pointer to buffer to store the read data
|
||||
* NumBytes - Number of bytes to read
|
||||
* Mode - The Mode that shall be used
|
||||
*
|
||||
* Return value:
|
||||
* Number of bytes read from the file/device
|
||||
*
|
||||
*/
|
||||
int _sys_read(FILEHANDLE hFile, unsigned char * pBuffer, unsigned NumBytes, int Mode) {
|
||||
(void)hFile;
|
||||
(void)pBuffer;
|
||||
(void)NumBytes;
|
||||
(void)Mode;
|
||||
return (0); // Not implemented
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* _sys_istty
|
||||
*
|
||||
* Function description:
|
||||
* This function shall return whether the opened file
|
||||
* is a console device or not.
|
||||
*
|
||||
* Parameters:
|
||||
* hFile - Handle to a file opened via _sys_open
|
||||
*
|
||||
* Return value:
|
||||
* 1 - Device is a console
|
||||
* 0 - Device is not a console
|
||||
*
|
||||
*/
|
||||
int _sys_istty(FILEHANDLE hFile) {
|
||||
if (hFile > 0x8000) {
|
||||
return (1);
|
||||
}
|
||||
return (0); // Not implemented
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* _sys_seek
|
||||
*
|
||||
* Function description:
|
||||
* Seeks via the file to a specific position
|
||||
*
|
||||
* Parameters:
|
||||
* hFile - Handle to a file opened via _sys_open
|
||||
* Pos -
|
||||
*
|
||||
* Return value:
|
||||
* int -
|
||||
*
|
||||
*/
|
||||
int _sys_seek(FILEHANDLE hFile, long Pos) {
|
||||
(void)hFile;
|
||||
(void)Pos;
|
||||
return (0); // Not implemented
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* _sys_ensure
|
||||
*
|
||||
* Function description:
|
||||
*
|
||||
*
|
||||
* Parameters:
|
||||
* hFile - Handle to a file opened via _sys_open
|
||||
*
|
||||
* Return value:
|
||||
* int -
|
||||
*
|
||||
*/
|
||||
int _sys_ensure(FILEHANDLE hFile) {
|
||||
(void)hFile;
|
||||
return (-1); // Not implemented
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* _sys_flen
|
||||
*
|
||||
* Function description:
|
||||
* Returns the length of the opened file handle
|
||||
*
|
||||
* Parameters:
|
||||
* hFile - Handle to a file opened via _sys_open
|
||||
*
|
||||
* Return value:
|
||||
* Length of the file
|
||||
*
|
||||
*/
|
||||
long _sys_flen(FILEHANDLE hFile) {
|
||||
(void)hFile;
|
||||
return (0); // Not implemented
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* _sys_tmpnam
|
||||
*
|
||||
* Function description:
|
||||
* This function converts the file number fileno for a temporary
|
||||
* file to a unique filename, for example, tmp0001.
|
||||
*
|
||||
* Parameters:
|
||||
* pBuffer - Pointer to a buffer to store the name
|
||||
* FileNum - file number to convert
|
||||
* MaxLen - Size of the buffer
|
||||
*
|
||||
* Return value:
|
||||
* 1 - Error
|
||||
* 0 - Success
|
||||
*
|
||||
*/
|
||||
int _sys_tmpnam2(char * pBuffer, int FileNum, unsigned MaxLen) {
|
||||
(void)pBuffer;
|
||||
(void)FileNum;
|
||||
(void)MaxLen;
|
||||
return (1); // Not implemented
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* _sys_command_string
|
||||
*
|
||||
* Function description:
|
||||
* This function shall execute a system command.
|
||||
*
|
||||
* Parameters:
|
||||
* cmd - Pointer to the command string
|
||||
* len - Length of the string
|
||||
*
|
||||
* Return value:
|
||||
* == NULL - Command was not successfully executed
|
||||
* == sCmd - Command was passed successfully
|
||||
*
|
||||
*/
|
||||
char * _sys_command_string(char * cmd, int len) {
|
||||
(void)len;
|
||||
return cmd; // Not implemented
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* _sys_exit
|
||||
*
|
||||
* Function description:
|
||||
* This function is called when the application returns from main
|
||||
*
|
||||
* Parameters:
|
||||
* ReturnCode - Return code from the main function
|
||||
*
|
||||
*
|
||||
*/
|
||||
void _sys_exit(int ReturnCode) {
|
||||
(void)ReturnCode;
|
||||
while (1); // Not implemented
|
||||
}
|
||||
|
||||
#if __ARMCC_VERSION >= 5000000
|
||||
/*********************************************************************
|
||||
*
|
||||
* stdout_putchar
|
||||
*
|
||||
* Function description:
|
||||
* Put a character to the stdout
|
||||
*
|
||||
* Parameters:
|
||||
* ch - Character to output
|
||||
*
|
||||
*
|
||||
*/
|
||||
int stdout_putchar(int ch) {
|
||||
(void)ch;
|
||||
return ch; // Not implemented
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/*************************** End of file ****************************/
|
||||
@@ -1,44 +0,0 @@
|
||||
/**************************************************************************
|
||||
* @file general_flash.h
|
||||
* @brief Заголовочны файл модуля работы с FLASH.
|
||||
*************************************************************************/
|
||||
#ifndef __FLASH_GENERAL_H_
|
||||
#define __FLASH_GENERAL_H_
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////---USER SETTINGS---/////////////////////////
|
||||
|
||||
|
||||
/////////////////////////---USER SETTINGS---/////////////////////////
|
||||
#include "mylibs_defs.h"
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////---DEFINES---////////////////////////////
|
||||
|
||||
////////////////////////////---DEFINES---////////////////////////////
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
///////////////////////---STRUCTURES & ENUMS---//////////////////////
|
||||
|
||||
///////////////////////---STRUCTURES & ENUMS---//////////////////////
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////---FUNCTIONS---///////////////////////////
|
||||
|
||||
HAL_StatusTypeDef FLASH_Enable_DualBankMode(void);
|
||||
HAL_StatusTypeDef FLASH_WriteProtection(uint32_t BankN, uint32_t WriteProtection);
|
||||
/* functions for reading bytes/halswords/words */
|
||||
uint8_t FLASH_Read_Byte(uint32_t add);
|
||||
uint16_t FLASH_Read_HalfWord(uint32_t add);
|
||||
uint32_t FLASH_Read_Word(uint32_t add);
|
||||
/* functions for writing bytes/halswords/words */
|
||||
HAL_StatusTypeDef FLASH_Write_Byte(uint32_t Address, uint8_t Data);
|
||||
HAL_StatusTypeDef FLASH_Write_HalfWord(uint32_t Address, uint16_t Data);
|
||||
HAL_StatusTypeDef FLASH_Write_Word(uint32_t Address, uint32_t Data);
|
||||
///////////////////////////---FUNCTIONS---///////////////////////////
|
||||
|
||||
#endif // __FLASH_GENERAL_H_
|
||||
@@ -1,237 +0,0 @@
|
||||
/**
|
||||
**************************************************************************
|
||||
* @file general_gpio.h
|
||||
* @brief Заголовочный файл для модуля инициализации портов и работы с ними.
|
||||
**************************************************************************
|
||||
* @defgroup MY_LIBS_GPIO GPIO Tools
|
||||
* @ingroup MYLIBS_PERIPHERAL
|
||||
* @brief Функции и макросы для удобной работы с GPIO.
|
||||
* @details
|
||||
Модуль предоставляет универсальные инструменты для работы с GPIO):
|
||||
- @ref MYLIBS_GPIO_GENERAL — инициализация и общие функции работы с портами.
|
||||
- @ref MYLIBS_GPIO_SWITCH — работа с GPIO как с кнопкой: чтение состояния,
|
||||
фильтрация дребезга, настройка активного уровня.
|
||||
- @ref MYLIBS_GPIO_LEDS — работа с GPIO как со светодиодом: включение,
|
||||
выключение, моргание и плавное затухание.
|
||||
|
||||
*************************************************************************/
|
||||
#ifndef __GPIO_GENERAL_H_
|
||||
#define __GPIO_GENERAL_H_
|
||||
|
||||
#include "mylibs_defs.h"
|
||||
|
||||
/**
|
||||
* @addtogroup GPIO_INIT Init defines
|
||||
* @ingroup MYLIBS_GPIO_GENERAL
|
||||
* @brief Настройка состояний кнопок и количества тиков в периоде ШИМ
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef local_time
|
||||
#define local_time() HAL_GetTick() ///< Локальное время
|
||||
#endif
|
||||
|
||||
#ifndef LED_PWM_TICKS
|
||||
#define LED_PWM_TICKS 15 ///< Количество тиков в периоде ШИМ
|
||||
#endif
|
||||
|
||||
#ifndef LED_ON
|
||||
#define LED_ON 1 ///< Состояние пина для включения светодиода
|
||||
#endif
|
||||
#ifndef LED_OFF
|
||||
#define LED_OFF 0 ///< Состояние пина для выключения светодиода
|
||||
#endif
|
||||
|
||||
#ifndef SW_ON
|
||||
#define SW_ON 1 ///< Состояние пина при нажатой кнопке
|
||||
#endif
|
||||
#ifndef SW_OFF
|
||||
#define SW_OFF 0 ///< Состояние пина при отжатой кнопке
|
||||
#endif
|
||||
|
||||
/** GPIO_INIT
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @brief Режимы работы светодиода
|
||||
* @ingroup MYLIBS_GPIO_LEDS
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
LED_IS_OFF = 0, ///< Светодиод выключен
|
||||
LED_IS_ON = 1, ///< Светодиод включен
|
||||
LED_IS_BLINKING = 2, ///< Моргание светодиодом
|
||||
LED_IS_FADING = 3, ///< Плавное моргание светодиодом
|
||||
}GPIO_LEDStateTypeDef;
|
||||
|
||||
/**
|
||||
* @brief Структура светодиода
|
||||
* @ingroup MYLIBS_GPIO_LEDS
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
GPIO_LEDStateTypeDef state; ///< Текущий режим работы светодиода
|
||||
|
||||
GPIO_TypeDef *LED_Port; ///< GPIO порт ножки светодиода
|
||||
uint32_t LED_Pin; ///< GPIO пин ножки светодиода
|
||||
|
||||
uint8_t LED_ActiveLvl; ///< Активный уровень ножки (при котором светодиод горит)
|
||||
uint32_t LED_Period; ///< Период моргания светодиода
|
||||
|
||||
uint32_t tickprev;
|
||||
}GPIO_LEDTypeDef;
|
||||
|
||||
/**
|
||||
* @brief Структура кнопки
|
||||
* @ingroup MYLIBS_GPIO_SWITCH
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
GPIO_TypeDef *Sw_Port; ///< GPIO порт ножки кнопки
|
||||
uint32_t Sw_Pin; ///< GPIO пин ножки кнопки
|
||||
|
||||
uint8_t Sw_ActiveLvl; ///< Активный уровень ножки (при котором кнопка нажата)
|
||||
uint32_t Sw_PrevState; ///< Предыдущее состояние кнопки
|
||||
uint32_t Sw_FilterDelay; ///< Фильтр от дребезга (в мс)
|
||||
|
||||
uint32_t tickprev;
|
||||
}GPIO_SwitchTypeDef;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////---FUNCTIONS---///////////////////////////
|
||||
/**
|
||||
* @addtogroup MYLIBS_GPIO_GENERAL General tools
|
||||
* @ingroup MY_LIBS_GPIO
|
||||
* @brief Общие функции/макросы для работы с GPIO
|
||||
* @par Пример использования:
|
||||
@code
|
||||
// Включаем тактирование порта GPIOA
|
||||
GPIO_Clock_Enable(GPIOA);
|
||||
@endcode
|
||||
* @{
|
||||
*/
|
||||
|
||||
HAL_StatusTypeDef GPIO_Clock_Enable(GPIO_TypeDef *GPIOx);
|
||||
|
||||
/** MYLIBS_GPIO_GENERAL
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup MYLIBS_GPIO_SWITCH Switch tools
|
||||
* @ingroup MY_LIBS_GPIO
|
||||
* @brief Функции для работы с GPIO, как с кнопкой
|
||||
* @par Пример использования:
|
||||
@code
|
||||
MX_GPIO_Init(); // инициализация пина аппаратная
|
||||
|
||||
// Инициализация кнопки на порте GPIOB, пин 0, активный уровень 1
|
||||
GPIO_SwitchTypeDef sw1;
|
||||
GPIO_Switch_Init(&sw1, GPIOB, GPIO_PIN_0, 1); // или дефайн SW_ON/SW_OFF
|
||||
|
||||
// Считываем состояние кнопки
|
||||
if(GPIO_Read_Switch(&sw1))
|
||||
{
|
||||
// Кнопка нажата
|
||||
LED_ON();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Кнопка отжата
|
||||
LED_OFF();
|
||||
}
|
||||
@endcode
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Инициализировать кнопку (структуру кнопки) */
|
||||
HAL_StatusTypeDef GPIO_Switch_Init(GPIO_SwitchTypeDef *sw, GPIO_TypeDef *GPIOx, uint32_t GPIO_PIN_X, uint8_t SW_On_State);
|
||||
/* Считать состоянии кнопки запуска */
|
||||
int GPIO_Read_Switch(GPIO_SwitchTypeDef *swstart);
|
||||
|
||||
/** MYLIBS_GPIO_SWITCH
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup MYLIBS_GPIO_LEDS LED tools
|
||||
* @ingroup MY_LIBS_GPIO
|
||||
* @brief Функции для работы с GPIO, для управления светодиодом
|
||||
* @par Пример использования:
|
||||
@code
|
||||
MX_GPIO_Init(); // инициализация пина аппаратная
|
||||
|
||||
// Инициализация светодиода на порте GPIOA, пин 5, активный уровень 0
|
||||
GPIO_LEDTypeDef led;
|
||||
GPIO_LED_Init(&led, GPIOA, GPIO_PIN_5, 0); // или дефайн LED_ON/LED_OFF
|
||||
|
||||
// Включение светодиода
|
||||
GPIO_LED_On(&led);
|
||||
|
||||
// Запуск моргания
|
||||
GPIO_LED_Blink_Start(&led, 500); // Период 500 мс
|
||||
|
||||
// В основном цикле
|
||||
while (1) {
|
||||
GPIO_LED_Dynamic_Handle(&led);
|
||||
}
|
||||
@endcode
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Инициализировать светодиод (структуру светодиода) */
|
||||
HAL_StatusTypeDef GPIO_LED_Init(GPIO_LEDTypeDef *led, GPIO_TypeDef *GPIOx, uint32_t GPIO_PIN_X, uint8_t LED_On_State);
|
||||
/* Включить светодиод */
|
||||
HAL_StatusTypeDef GPIO_LED_On (GPIO_LEDTypeDef *led);
|
||||
/* Выключить светодиод */
|
||||
HAL_StatusTypeDef GPIO_LED_Off (GPIO_LEDTypeDef *led);
|
||||
/* Выставить светодиод по переменной */
|
||||
HAL_StatusTypeDef GPIO_LED_Set (GPIO_LEDTypeDef *led, uint8_t led_state);
|
||||
/* Активировать моргание светодиодом */
|
||||
HAL_StatusTypeDef GPIO_LED_Blink_Start (GPIO_LEDTypeDef *led, uint32_t period);
|
||||
/* Активировать моргание светодиодом */
|
||||
HAL_StatusTypeDef GPIO_LED_Fading_Start(GPIO_LEDTypeDef *led, uint32_t period);
|
||||
/* Управление динамическими режимами свечения светодиода */
|
||||
void GPIO_LED_Dynamic_Handle(GPIO_LEDTypeDef *led);
|
||||
|
||||
/** MYLIBS_GPIO_LEDS
|
||||
* @}
|
||||
*/
|
||||
///////////////////////////---FUNCTIONS---///////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* @cond GPIO_INTERNAL
|
||||
*/
|
||||
|
||||
// /**
|
||||
// * @brief Маппинг альтернативной функции SPI между GPIO
|
||||
// * @ingroup MYLIBS_GPIO_GENERAL
|
||||
// */
|
||||
// #define SPI_Alternate_Mapping(INSTANCE) \
|
||||
// ((((INSTANCE) == TIM1) || ((INSTANCE) == TIM2))? GPIO_AF1_TIM1: \
|
||||
// (((INSTANCE) == TIM3) || ((INSTANCE) == TIM4) || ((INSTANCE) == TIM5))? GPIO_AF2_TIM3: \
|
||||
// (((INSTANCE) == TIM8) || ((INSTANCE) == TIM9) || ((INSTANCE) == TIM10) || ((INSTANCE) == TIM11))? GPIO_AF3_TIM8: \
|
||||
// (((INSTANCE) == TIM12) || ((INSTANCE) == TIM13) || ((INSTANCE) == TIM14))? GPIO_AF9_TIM12: \
|
||||
// (0))
|
||||
|
||||
|
||||
/**
|
||||
* @brief Маппинг альтернативной функции TIM между GPIO
|
||||
* @ingroup MYLIBS_GPIO_GENERAL
|
||||
*/
|
||||
#define GPIO_TIM_Alternate_Mapping(INSTANCE) \
|
||||
((((INSTANCE) == TIM1) || ((INSTANCE) == TIM2))? GPIO_AF1_TIM1: \
|
||||
(((INSTANCE) == TIM3) || ((INSTANCE) == TIM4) || ((INSTANCE) == TIM5))? GPIO_AF2_TIM3: \
|
||||
(((INSTANCE) == TIM8) || ((INSTANCE) == TIM9) || ((INSTANCE) == TIM10) || ((INSTANCE) == TIM11))? GPIO_AF3_TIM8: \
|
||||
(((INSTANCE) == TIM12) || ((INSTANCE) == TIM13) || ((INSTANCE) == TIM14))? GPIO_AF9_TIM12: \
|
||||
(0))
|
||||
|
||||
|
||||
/** @endcond */
|
||||
|
||||
#endif // __GPIO_GENERAL_H_
|
||||
@@ -1,170 +0,0 @@
|
||||
/**
|
||||
**************************************************************************
|
||||
* @file general_spi.h
|
||||
* @brief Заголовочный файл для модуля инициализации SPI.
|
||||
**************************************************************************
|
||||
* @defgroup MY_LIBS_SPI SPI Tools
|
||||
* @ingroup MYLIBS_PERIPHERAL
|
||||
* @brief Функции и макросы для удобной работы с SPI.
|
||||
* @details
|
||||
Модуль предоставляет функции для базовой инициализации SPI
|
||||
|
||||
|
||||
@par Пример использования:
|
||||
@code
|
||||
// Структура настроек SPI
|
||||
SPI_SettingsTypeDef spi1Settings;
|
||||
|
||||
void SPI1_Init(void)
|
||||
{
|
||||
// Настройка SPI1 как Master, 8 бит, полный дуплекс
|
||||
spi1Settings.hspi.Instance = SPI1;
|
||||
spi1Settings.hspi.Init.Mode = SPI_MODE_MASTER;
|
||||
spi1Settings.hspi.Init.Direction = SPI_DIRECTION_2LINES;
|
||||
spi1Settings.hspi.Init.DataSize = SPI_DATASIZE_8BIT;
|
||||
spi1Settings.hspi.Init.CLKPolarity = SPI_POLARITY_LOW;
|
||||
spi1Settings.hspi.Init.CLKPhase = SPI_PHASE_1EDGE;
|
||||
spi1Settings.hspi.Init.NSS = SPI_NSS_SOFT;
|
||||
spi1Settings.hspi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
|
||||
spi1Settings.hspi.Init.FirstBit = SPI_FIRSTBIT_MSB;
|
||||
spi1Settings.hspi.Init.TIMode = SPI_TIMODE_DISABLE;
|
||||
spi1Settings.hspi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
|
||||
|
||||
// Настройка GPIO
|
||||
spi1Settings.CLK_GPIOx = GPIOA;
|
||||
spi1Settings.CLK_PIN = GPIO_PIN_5;
|
||||
spi1Settings.CLK_GPIO_AlternageFunc = GPIO_AF5_SPI1;
|
||||
|
||||
spi1Settings.MISO_GPIOx = GPIOA;
|
||||
spi1Settings.MISO_PIN = GPIO_PIN_6;
|
||||
spi1Settings.MISO_GPIO_AlternageFunc = GPIO_AF5_SPI1;
|
||||
|
||||
spi1Settings.MOSI_GPIOx = GPIOA;
|
||||
spi1Settings.MOSI_PIN = GPIO_PIN_7;
|
||||
spi1Settings.MOSI_GPIO_AlternageFunc = GPIO_AF5_SPI1;
|
||||
|
||||
// Инициализация SPI
|
||||
if(SPI_Base_Init(&spi1Settings) != HAL_OK)
|
||||
{
|
||||
// Обработка ошибки
|
||||
Error_Handler();
|
||||
}
|
||||
}
|
||||
@endcode
|
||||
|
||||
|
||||
|
||||
* @note Требуется подключение модуля SPI в библиотеке HAL
|
||||
@code
|
||||
#define HAL_SPI_MODULE_ENABLED
|
||||
@endcode
|
||||
* @{
|
||||
*************************************************************************/
|
||||
#ifndef __SPI_GENERAL_H_
|
||||
#define __SPI_GENERAL_H_
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////---USER SETTINGS---/////////////////////////
|
||||
/**
|
||||
* @addtogroup SPI_INIT Init defines
|
||||
* @ingroup MY_LIBS_SPI
|
||||
* @brief Настройка SPI
|
||||
* @{
|
||||
*/
|
||||
#define HAL_SPI_MODULE_ENABLED ///< Включение HAL SPI
|
||||
|
||||
#define USE_SPI1 ///< Включить SPI1 в @ref SPI_MspInit
|
||||
#define USE_SPI2 ///< Включить SPI2 в @ref SPI_MspInit
|
||||
#define USE_SPI3 ///< Включить SPI3 в @ref SPI_MspInit
|
||||
/** SPI_INIT
|
||||
* @}
|
||||
*/
|
||||
/////////////////////////---USER SETTINGS---/////////////////////////
|
||||
#include "mylibs_defs.h"
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////---DEFINES---////////////////////////////
|
||||
|
||||
|
||||
|
||||
////////////////////////////---DEFINES---////////////////////////////
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
///////////////////////---STRUCTURES & ENUMS---//////////////////////
|
||||
/**
|
||||
* @brief Структура настроек SPI
|
||||
* @details Содержит все необходимые параметры для инициализации SPI,
|
||||
* включая GPIO и DMA.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
SPI_HandleTypeDef hspi; ///< HAL handle SPI
|
||||
|
||||
GPIO_TypeDef *CLK_GPIOx; ///< Порт CLK
|
||||
uint32_t CLK_PIN; ///< Пин CLK
|
||||
uint32_t CLK_GPIO_AlternageFunc; ///< Альтернативная функция для CLK
|
||||
|
||||
GPIO_TypeDef *MISO_GPIOx; ///< Порт MISO
|
||||
uint32_t MISO_PIN; ///< Пин MISO
|
||||
uint32_t MISO_GPIO_AlternageFunc; ///< Альтернативная функция для MISO
|
||||
|
||||
GPIO_TypeDef *MOSI_GPIOx; ///< Порт MOSI
|
||||
uint32_t MOSI_PIN; ///< Пин MOSI
|
||||
uint32_t MOSI_GPIO_AlternageFunc; ///< Альтернативная функция для MOSI
|
||||
|
||||
DMA_Stream_TypeDef *DMAChannel; ///< Канал DMA (NULL если не нужен)
|
||||
uint32_t DMA_CHANNEL_X; ///< Номер канала DMA (0 если не нужен)
|
||||
|
||||
} SPI_SettingsTypeDef;
|
||||
///////////////////////---STRUCTURES & ENUMS---//////////////////////
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////---FUNCTIONS---///////////////////////////
|
||||
|
||||
/* Инициализация SPI с использованием структуры настроек */
|
||||
HAL_StatusTypeDef SPI_Base_Init(SPI_SettingsTypeDef *sspi);
|
||||
|
||||
/* Проверка корректности структуры настроек SPI */
|
||||
HAL_StatusTypeDef SPI_Check_Init_Struct(SPI_SettingsTypeDef *sspi);
|
||||
|
||||
/* Инициализация тактирования и прерываний для выбранного SPI */
|
||||
void SPI_MspInit(SPI_HandleTypeDef *hspi);
|
||||
|
||||
/* Деинициализация тактирования и прерываний для выбранного SPI */
|
||||
void SPI_MspDeInit(SPI_HandleTypeDef *hspi);
|
||||
|
||||
|
||||
/**
|
||||
* @cond SPI_INTERNAL
|
||||
*/
|
||||
|
||||
/* Настройка GPIO для SPI */
|
||||
void SPI_GPIO_Init(SPI_SettingsTypeDef *sspi);
|
||||
|
||||
/* Настройка DMA для SPI */
|
||||
void SPI_DMA_Init(SPI_HandleTypeDef *hspi, DMA_HandleTypeDef *hdma_rx, DMA_Stream_TypeDef *DMAChannel, uint32_t DMA_CHANNEL_X);
|
||||
|
||||
#ifndef __USER_LINKDMA
|
||||
/**
|
||||
* @brief Аналог HAL макроса для привязки DMA к UART.
|
||||
* @note @ref __HAL_LINKDMA.
|
||||
*/
|
||||
#define __USER_LINKDMA(__HANDLE__, __PPP_DMA_FIELD__, __DMA_HANDLE__) \
|
||||
do{ \
|
||||
(__HANDLE__)->__PPP_DMA_FIELD__ = (__DMA_HANDLE__); \
|
||||
(__DMA_HANDLE__)->Parent = (__HANDLE__);} while(0U)
|
||||
#endif
|
||||
|
||||
/** @endcond */
|
||||
///////////////////////////---FUNCTIONS---///////////////////////////
|
||||
|
||||
#endif // __SPI_GENERAL_H_
|
||||
|
||||
/** MY_LIBS_SPI
|
||||
* @}
|
||||
*/
|
||||
@@ -1,301 +0,0 @@
|
||||
/**
|
||||
**************************************************************************
|
||||
* @file general_tim.h
|
||||
* @brief Заголовочный файл для модуля инициализации таймеров и работы с ними.
|
||||
**************************************************************************
|
||||
* @defgroup MY_LIBS_TIM TIM Tools
|
||||
* @ingroup MYLIBS_PERIPHERAL
|
||||
* @brief Функции и макросы для удобной работы с TIM.
|
||||
* @details
|
||||
Модуль предоставляет универсальные инструменты для работы с TIM:
|
||||
- @ref MYLIBS_TIM_GENERAL — базовая инициализация таймеров и прерываний.
|
||||
- @ref MYLIBS_TIM_DELAY — функции задержки через таймеры (blocking и non-blocking).
|
||||
- @ref MYLIBS_TIM_OC — настройка каналов Output Compare и PWM.
|
||||
- @ref MYLIBS_TIM_ENCODER — работа с энкодерами, чтение положения и кнопки.
|
||||
|
||||
* @note Требуется подключение модуля TIM в библиотеке HAL и GPIO (@ref MY_LIBS_GPIO) из MyLibs
|
||||
@code
|
||||
#define HAL_TIM_MODULE_ENABLED
|
||||
@endcode
|
||||
*************************************************************************/
|
||||
#ifndef __TIM_GENERAL_H_
|
||||
#define __TIM_GENERAL_H_
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////---USER SETTINGS---/////////////////////////
|
||||
/**
|
||||
* @addtogroup TIM_INIT Init defines
|
||||
* @ingroup MYLIBS_TIM_GENERAL
|
||||
* @brief Настройка таймеров
|
||||
* @{
|
||||
*/
|
||||
#define HAL_TIM_MODULE_ENABLED
|
||||
|
||||
#define USE_TIM1 ///< Включить TIM1 в @ref TIM_Base_MspInit
|
||||
#define USE_TIM2 ///< Включить TIM2 в @ref TIM_Base_MspInit
|
||||
#define USE_TIM3 ///< Включить TIM3 в @ref TIM_Base_MspInit
|
||||
#define USE_TIM4 ///< Включить TIM4 в @ref TIM_Base_MspInit
|
||||
#define USE_TIM5 ///< Включить TIM5 в @ref TIM_Base_MspInit
|
||||
#define USE_TIM6 ///< Включить TIM6 в @ref TIM_Base_MspInit
|
||||
#define USE_TIM7 ///< Включить TIM7 в @ref TIM_Base_MspInit
|
||||
#define USE_TIM8 ///< Включить TIM8 в @ref TIM_Base_MspInit
|
||||
#define USE_TIM9 ///< Включить TIM9 в @ref TIM_Base_MspInit
|
||||
#define USE_TIM10 ///< Включить TIM10 в @ref TIM_Base_MspInit
|
||||
#define USE_TIM11 ///< Включить TIM11 в @ref TIM_Base_MspInit
|
||||
#define USE_TIM12 ///< Включить TIM12 в @ref TIM_Base_MspInit
|
||||
#define USE_TIM13 ///< Включить TIM13 в @ref TIM_Base_MspInit
|
||||
#define USE_TIM14 ///< Включить TIM14 в @ref TIM_Base_MspInit
|
||||
/** TIM_INIT
|
||||
* @}
|
||||
*/
|
||||
/////////////////////////---USER SETTINGS---/////////////////////////
|
||||
#include "mylibs_defs.h"
|
||||
#include "general_gpio.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////---DEFINES---////////////////////////////
|
||||
#define TIM_IT_CONF_Pos 0
|
||||
//#define TIM_PWM_CONF_Pos 1
|
||||
//#define TIM_CLCK_SRC_CONF_Pos 2
|
||||
//#define TIM_SLAVE_CONF_Pos 3
|
||||
//#define TIM_MASTER_CONF_Pos 4
|
||||
//#define TIM_BDTR_CONF_Pos 5
|
||||
|
||||
#define TIM_IT_CONF (1<<(TIM_IT_CONF_Pos))
|
||||
//#define TIM_PWM_CONF (1<<(TIM_PWM_Pos))
|
||||
|
||||
////////////////////////////---DEFINES---////////////////////////////]
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
///////////////////////---STRUCTURES & ENUMS---//////////////////////
|
||||
/**
|
||||
* @brief Режим прерываний таймера
|
||||
* @ingroup MYLIBS_TIM_GENERAL
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
TIM_DEFAULT = 0, ///< Прерываний отключены
|
||||
TIM_IT_MODE = TIM_IT_CONF, ///< Прерываний включены
|
||||
// TIM_PWM_MODE = TIM_PWM_ENABLE,
|
||||
// TIM_PWM_IT_MODE = TIM_PWM_ENABLE | TIM_IT_CONF,
|
||||
}TIM_ITModeTypeDef;
|
||||
|
||||
/**
|
||||
* @brief Длительность тика таймера (частота тактирования таймера)
|
||||
* @ingroup MYLIBS_TIM_GENERAL
|
||||
* @details enum дает базовые длительности, но можно выставить другие
|
||||
* (напр 500 - 0.5 мс)
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
TIM_Base_Disable = 0, ///< Таймер отключен
|
||||
TIM_TickBase_1US = 1, ///< Таймер тактируется с частотой 1 МГц
|
||||
TIM_TickBase_10US = 10, ///< Таймер тактируется с частотой 100 кГц
|
||||
TIM_TickBase_100US = 100, ///< Таймер тактируется с частотой 10 кГц
|
||||
TIM_TickBase_1MS = 1000, ///< Таймер тактируется с частотой 1 кГц
|
||||
TIM_TickBase_10MS = 10000, ///< Таймер тактируется с частотой 100 Гц
|
||||
TIM_TickBase_100MS = 100000, ///< Таймер тактируется с частотой 10 Гц
|
||||
}TIM_MHzTickBaseTypeDef;
|
||||
|
||||
/**
|
||||
* @brief Структура инициализации таймера
|
||||
* @ingroup MYLIBS_TIM_GENERAL
|
||||
* @details
|
||||
* Содержит все базовые структуры, которые нужны для инициализации таймера.
|
||||
* Если структуры настроек не заданы, то они заполнятся сами дефолтными параметрами
|
||||
*
|
||||
* Также высокоуровневые настройки частоты работы таймера.
|
||||
* Если какая-либо высокоуровневая настройка не задана, то
|
||||
* по возможности берется низкоуровневая настройка из структур
|
||||
*/
|
||||
typedef struct // struct with settings for custom function
|
||||
{
|
||||
TIM_HandleTypeDef htim; ///< HAL handle таймера
|
||||
TIM_ClockConfigTypeDef sClockSourceConfig; ///< Настройки тактирования таймера
|
||||
TIM_SlaveConfigTypeDef sSlaveConfig; ///< Настройки слейв режима таймера
|
||||
TIM_MasterConfigTypeDef sMasterConfig; ///< Настройки мастер режима таймера
|
||||
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig; ///< Настройки дедтаймов таймера
|
||||
|
||||
TIM_ITModeTypeDef sTimMode; ///< Настройки прерывания таймера
|
||||
TIM_MHzTickBaseTypeDef sTickBaseUS; ///< Длительность одного тика
|
||||
uint8_t sTickBasePrescaler; ///< Дополнительный делитель, для удобного деления @ref sTickBaseUS
|
||||
float sTimAHBFreqMHz; ///< Частота шины тактирования таймера
|
||||
float sTimFreqHz; ///< Желаемая частота таймера
|
||||
|
||||
}TIM_SettingsTypeDef;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Структура инициализации енкодера
|
||||
* @ingroup MYLIBS_TIM_ENCODER
|
||||
* @details
|
||||
* Содержит все базовые структуры, которые нужны для инициализации таймера.
|
||||
* Если структуры настроек не заданы, то они заполнятся сами дефолтными параметрами
|
||||
*
|
||||
* Также высокоуровневые настройки частоты работы таймера.
|
||||
* Если какая-либо высокоуровневая настройка не задана, то
|
||||
* по возможности берется низкоуровневая настройка из структур
|
||||
*/
|
||||
typedef struct // struct with variables for encoder
|
||||
{
|
||||
int16_t Encoder_Diff; ///< Считанная разница
|
||||
uint16_t Encoder_Shdw; ///< Последние считанные тики
|
||||
|
||||
TIM_HandleTypeDef *htim; ///< Указатель на HAL handle таймера
|
||||
TIM_Encoder_InitTypeDef sConfig; ///< Указатель на структуру настройки энкодера
|
||||
|
||||
GPIO_TypeDef *GPIOx; ///< Порт, куда подключается энкодер
|
||||
uint32_t GPIO_PIN_TI1; ///< Пин, куда подключается канал TI1
|
||||
uint32_t GPIO_PIN_TI2; ///< Пин, куда подключается канал TI2
|
||||
uint32_t GPIO_PIN_SW; ///< Пин, куда кнопка энкодера (если есть)
|
||||
|
||||
GPIO_SwitchTypeDef Sw; ///< Структура кнопки
|
||||
|
||||
}TIM_EncoderTypeDef;
|
||||
///////////////////////---STRUCTURES & ENUMS---//////////////////////
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////---FUNCTIONS---///////////////////////////
|
||||
/**
|
||||
* @addtogroup MYLIBS_TIM_GENERAL General tools
|
||||
* @ingroup MY_LIBS_TIM
|
||||
* @brief Функции для базовой инициализации таймеров
|
||||
* @par Пример использования:
|
||||
@code
|
||||
TIM_SettingsTypeDef tim2Settings;
|
||||
|
||||
void TIM2_Init(void)
|
||||
{
|
||||
// Настройка таймера TIM2 на 1 кГц с прерываниями с шагом таймера 10 мкс
|
||||
tim2Settings.htim.Instance = TIM2;
|
||||
tim2Settings.sTimMode = TIM_IT_MODE;
|
||||
tim2Settings.sTickBaseUS = TIM_TickBase_10US;
|
||||
tim2Settings.sTickBasePrescaler = 1;
|
||||
tim2Settings.sTimFreqHz = 1000; // 1 кГц
|
||||
tim2Settings.sTimAHBFreqMHz = 72000000; // Hz
|
||||
|
||||
if(TIM_Base_Init(&tim2Settings) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
}
|
||||
@endcode
|
||||
* @{
|
||||
*/
|
||||
/* Initialize TIM with TIM_SettingsTypeDef structure */
|
||||
HAL_StatusTypeDef TIM_Base_Init(TIM_SettingsTypeDef* stim);
|
||||
/* Initialize TIMs clock and interrupt */
|
||||
void TIM_Base_MspInit(TIM_HandleTypeDef* htim, TIM_ITModeTypeDef it_mode);
|
||||
/* DeInitialize TIMs clock and interrupt */
|
||||
void TIM_Base_MspDeInit(TIM_HandleTypeDef* htim);
|
||||
/** MYLIBS_TIM_GENERAL
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup MYLIBS_TIM_DELAY Delay tools
|
||||
* @ingroup MY_LIBS_TIM
|
||||
* @brief Функции для формирования задержек с помощью таймеров
|
||||
* @par Пример использования:
|
||||
@code
|
||||
TIM_HandleTypeDef htim2;
|
||||
|
||||
// блокирующая задержка 500 тиков таймера
|
||||
LED_ON();
|
||||
TIM_Delay(&htim2, 500);
|
||||
LED_OFF();
|
||||
|
||||
|
||||
while(1)
|
||||
{
|
||||
// не блокирующая задержка 200 тиков таймера
|
||||
if(TIM_Delay_NonBlocking(&htim2, 200) == HAL_OK)
|
||||
{
|
||||
TIM_Delay_Start(&htim2);
|
||||
LED_TOOGLE();
|
||||
}
|
||||
}
|
||||
@endcode
|
||||
* @{
|
||||
*/
|
||||
/* Start delay via TIM */
|
||||
HAL_StatusTypeDef TIM_Delay_Start(TIM_HandleTypeDef *htim);
|
||||
/* Delay via TIM */
|
||||
HAL_StatusTypeDef TIM_Delay(TIM_HandleTypeDef *htim, uint16_t delay);
|
||||
/* Wait Delay via TIM without blocking app */
|
||||
HAL_StatusTypeDef TIM_Delay_NonBlocking(TIM_HandleTypeDef *htim, uint16_t delay);
|
||||
/** MYLIBS_TIM_DELAY
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup MYLIBS_TIM_OC PWM/OC Channels tools
|
||||
* @ingroup MY_LIBS_TIM
|
||||
* @brief Функции для инициализации базовых функций каналов таймера
|
||||
* @par Пример использования:
|
||||
@code
|
||||
void PWM_Channel_Init_Example(void)
|
||||
{
|
||||
TIM_HandleTypeDef htim3;
|
||||
TIM_OC_InitTypeDef sConfigOC;
|
||||
GPIO_TypeDef *GPIOx = GPIOB;
|
||||
uint32_t PWM_PIN = GPIO_PIN_0;
|
||||
|
||||
// Настройка таймера и канала PWM
|
||||
TIM_Output_PWM_Init(&htim3, &sConfigOC, TIM_CHANNEL_1, GPIOx, PWM_PIN);
|
||||
|
||||
// Настройка компаратора OC
|
||||
TIM_OC_Comparator_Init(&htim3, TIM_CHANNEL_1);
|
||||
}
|
||||
@endcode
|
||||
* @{
|
||||
*/
|
||||
/* Initialize PWM Channel and GPIO for output */
|
||||
HAL_StatusTypeDef TIM_Output_PWM_Init(TIM_HandleTypeDef *htim, TIM_OC_InitTypeDef *sConfigOC, uint32_t TIM_CHANNEL, GPIO_TypeDef *GPIOx, uint32_t PWM_PIN);
|
||||
/* Initialize OC Comparator */
|
||||
HAL_StatusTypeDef TIM_OC_Comparator_Init(TIM_HandleTypeDef *htim, uint32_t TIM_CHANNEL);
|
||||
/** MYLIBS_TIM_ENCODER
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup MYLIBS_TIM_ENCODER Encoder tools
|
||||
* @ingroup MY_LIBS_TIM
|
||||
* @brief Функции для считывания энкодера
|
||||
* @par Пример использования:
|
||||
@code
|
||||
TIM_EncoderTypeDef henc1;
|
||||
TIM_HandleTypeDef htim4;
|
||||
|
||||
// инициализация
|
||||
henc1.htim = &htim4;
|
||||
henc1.GPIOx = GPIOA;
|
||||
henc1.GPIO_PIN_TI1 = GPIO_PIN_0;
|
||||
henc1.GPIO_PIN_TI2 = GPIO_PIN_1;
|
||||
TIM_Encoder_Init(&henc1, &htim4);
|
||||
|
||||
// считывание энкодера и кнопки
|
||||
int16_t delta = TIM_Encoder_Read(&henc1);
|
||||
setpoint_tmp += delta;
|
||||
if(TIM_Encoder_ReadSwitch(&henc1))
|
||||
{
|
||||
setpoint = setpoint_tmp; // подтвердить новое значение
|
||||
}
|
||||
@endcode
|
||||
* @{
|
||||
*/
|
||||
/* Initialize TIM Encoder functional */
|
||||
HAL_StatusTypeDef TIM_Encoder_Init(TIM_EncoderTypeDef *henc1, TIM_HandleTypeDef *htim);
|
||||
/* Считать энкодер */
|
||||
HAL_StatusTypeDef TIM_Encoder_Read(TIM_EncoderTypeDef *henc);
|
||||
/* Считать кнопку энкодера */
|
||||
int TIM_Encoder_ReadSwitch(TIM_EncoderTypeDef *henc);
|
||||
/** MYLIBS_TIM_ENCODER
|
||||
* @}
|
||||
*/
|
||||
///////////////////////////---FUNCTIONS---///////////////////////////
|
||||
|
||||
|
||||
#endif // __TIM_GENERAL_H_
|
||||
@@ -1,156 +0,0 @@
|
||||
/**
|
||||
**************************************************************************
|
||||
* @file general_uart.h
|
||||
* @brief Заголовочный файл для модуля инициализации UART.
|
||||
**************************************************************************
|
||||
* @defgroup MY_LIBS_UART UART Tools
|
||||
* @ingroup MYLIBS_PERIPHERAL
|
||||
* @brief Функции и макросы для удобной работы с UART.
|
||||
* @details
|
||||
Модуль предоставляет функции для базовой инициализации UART
|
||||
|
||||
|
||||
@par Пример использования:
|
||||
@code
|
||||
// Структура настроек UART
|
||||
UART_SettingsTypeDef uart2Settings;
|
||||
|
||||
void UART2_Init(void)
|
||||
{
|
||||
// Настройка UART2 с 115200 бод, 8 бит, 1 стоп-бит, без паритета
|
||||
uart2Settings.huart.Instance = USART2;
|
||||
uart2Settings.huart.Init.BaudRate = 115200;
|
||||
uart2Settings.huart.Init.WordLength = UART_WORDLENGTH_8B;
|
||||
uart2Settings.huart.Init.StopBits = UART_STOPBITS_1;
|
||||
uart2Settings.huart.Init.Parity = UART_PARITY_NONE;
|
||||
uart2Settings.huart.Init.Mode = UART_MODE_TX_RX;
|
||||
uart2Settings.huart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
|
||||
uart2Settings.huart.Init.OverSampling = UART_OVERSAMPLING_16;
|
||||
|
||||
// Настройка GPIO
|
||||
uart2Settings.GPIOx = GPIOA;
|
||||
uart2Settings.GPIO_PIN_TX = GPIO_PIN_2;
|
||||
uart2Settings.GPIO_PIN_RX = GPIO_PIN_3;
|
||||
|
||||
// DMA не используется в этом примере
|
||||
uart2Settings.DMAChannel = NULL;
|
||||
uart2Settings.DMA_CHANNEL_X = 0;
|
||||
|
||||
// Инициализация UART
|
||||
if(UART_Base_Init(&uart2Settings) != HAL_OK)
|
||||
{
|
||||
// Обработка ошибки
|
||||
Error_Handler();
|
||||
}
|
||||
}
|
||||
@endcode
|
||||
|
||||
* @note Требуется подключение модуля UART в библиотеке HAL
|
||||
@code
|
||||
#define HAL_UART_MODULE_ENABLED
|
||||
@endcode
|
||||
* @{
|
||||
*************************************************************************/
|
||||
#ifndef __UART_GENERAL_H_
|
||||
#define __UART_GENERAL_H_
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////---USER SETTINGS---/////////////////////////
|
||||
/**
|
||||
* @addtogroup UART_INIT Init defines
|
||||
* @ingroup MY_LIBS_UART
|
||||
* @brief Настройка UART
|
||||
* @{
|
||||
*/
|
||||
#define HAL_UART_MODULE_ENABLED ///< Включение HAL UART
|
||||
|
||||
#define USE_USART1 ///< Включить USART1 в @ref UART_MspInit
|
||||
#define USE_USART2 ///< Включить USART2 в @ref UART_MspInit
|
||||
#define USE_USART3 ///< Включить USART3 в @ref UART_MspInit
|
||||
#define USE_UART4 ///< Включить UART4 в @ref UART_MspInit
|
||||
#define USE_UART5 ///< Включить UART5 в @ref UART_MspInit
|
||||
#define USE_USART6 ///< Включить USART6 в @ref UART_MspInit
|
||||
/** UART_INIT
|
||||
* @}
|
||||
*/
|
||||
/////////////////////////---USER SETTINGS---/////////////////////////
|
||||
#include "mylibs_defs.h"
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////---DEFINES---////////////////////////////
|
||||
|
||||
|
||||
|
||||
////////////////////////////---DEFINES---////////////////////////////
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
///////////////////////---STRUCTURES & ENUMS---//////////////////////
|
||||
/**
|
||||
* @brief Структура настроек UART
|
||||
* @details Содержит все необходимые параметры для инициализации UART,
|
||||
* включая GPIO и DMA.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
UART_HandleTypeDef huart; ///< HAL handle UART
|
||||
|
||||
GPIO_TypeDef *GPIOx; ///< Порт для UART
|
||||
uint16_t GPIO_PIN_RX; ///< Пин приема
|
||||
uint16_t GPIO_PIN_TX; ///< Пин передачи
|
||||
|
||||
DMA_Stream_TypeDef *DMAChannel; ///< Канал DMA (NULL если не нужен)
|
||||
uint32_t DMA_CHANNEL_X; ///< Номер канала DMA (0 если не нужен)
|
||||
|
||||
} UART_SettingsTypeDef;
|
||||
|
||||
///////////////////////---STRUCTURES & ENUMS---//////////////////////
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////---FUNCTIONS---///////////////////////////
|
||||
|
||||
/* Инициализация UART с использованием структуры настроек */
|
||||
HAL_StatusTypeDef UART_Base_Init(UART_SettingsTypeDef *suart);
|
||||
|
||||
/* Проверка корректности структуры настроек UART */
|
||||
HAL_StatusTypeDef UART_Check_Init_Struct(UART_SettingsTypeDef *suart);
|
||||
|
||||
/* Инициализация тактирования и прерываний для выбранного UART */
|
||||
void UART_MspInit(UART_HandleTypeDef *huart);
|
||||
|
||||
/* Деинициализация тактирования и прерываний для выбранного UART */
|
||||
void UART_MspDeInit(UART_HandleTypeDef *huart);
|
||||
|
||||
|
||||
/**
|
||||
* @cond UART_INTERNAL
|
||||
*/
|
||||
|
||||
/* Настройка GPIO для UART */
|
||||
void UART_GPIO_Init(GPIO_TypeDef *GPIOx, uint16_t GPIO_PIN_RX, uint16_t GPIO_PIN_TX);
|
||||
|
||||
/* Настройка DMA для UART */
|
||||
void UART_DMA_Init(UART_HandleTypeDef *huart, DMA_HandleTypeDef *hdma_rx, DMA_Stream_TypeDef *DMAChannel, uint32_t DMA_CHANNEL_X);
|
||||
|
||||
#ifndef __USER_LINKDMA
|
||||
/**
|
||||
* @brief Аналог HAL макроса для привязки DMA к UART.
|
||||
* @note @ref __HAL_LINKDMA.
|
||||
*/
|
||||
#define __USER_LINKDMA(__HANDLE__, __PPP_DMA_FIELD__, __DMA_HANDLE__) \
|
||||
do{ \
|
||||
(__HANDLE__)->__PPP_DMA_FIELD__ = (__DMA_HANDLE__); \
|
||||
(__DMA_HANDLE__)->Parent = (__HANDLE__);} while(0U)
|
||||
#endif
|
||||
|
||||
/** @endcond */
|
||||
///////////////////////////---FUNCTIONS---///////////////////////////
|
||||
|
||||
#endif // __UART_GENERAL_H_
|
||||
|
||||
/** MY_LIBS_UART
|
||||
* @}
|
||||
*/
|
||||
@@ -1,192 +0,0 @@
|
||||
#include "__general_flash.h"
|
||||
FLASH_EraseInitTypeDef EraseInitStruct;
|
||||
extern HAL_StatusTypeDef res_hal;
|
||||
unsigned CRC_Update;
|
||||
//uint32_t PAGE_OFFSET = ((uint32_t)((4-1) * 0x0400));
|
||||
uint32_t PAGE_NUMB = 127;
|
||||
|
||||
|
||||
/* Записать в память данные, произвольного размера */
|
||||
HAL_StatusTypeDef FLASH_Write_Data(uint32_t* Address, uint8_t* Data, int Data_size)
|
||||
{
|
||||
HAL_StatusTypeDef res_hal;
|
||||
|
||||
int data_cnt = 0;
|
||||
uint32_t adr;
|
||||
uint32_t word_data;
|
||||
|
||||
|
||||
res_hal = HAL_FLASH_Unlock();
|
||||
if (res_hal != HAL_OK) return res_hal;
|
||||
|
||||
for (adr = *Address; adr < *Address + Data_size; adr = adr + 4)
|
||||
{
|
||||
|
||||
|
||||
word_data = (
|
||||
Data[data_cnt] |
|
||||
Data[data_cnt + 1] << 8 |
|
||||
Data[data_cnt + 2] << 16 |
|
||||
Data[data_cnt + 3] << 24);
|
||||
|
||||
res_hal = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, adr, word_data);
|
||||
|
||||
if (res_hal != HAL_OK) return res_hal;
|
||||
|
||||
data_cnt += 4;
|
||||
}
|
||||
|
||||
*Address += Data_size;
|
||||
res_hal = HAL_FLASH_Lock();
|
||||
|
||||
return res_hal;
|
||||
}
|
||||
|
||||
|
||||
|
||||
HAL_StatusTypeDef FLASH_Enable_DualBankMode(void)
|
||||
{
|
||||
HAL_StatusTypeDef res_hal;
|
||||
FLASH_AdvOBProgramInitTypeDef OB_DualBank;
|
||||
|
||||
|
||||
res_hal = HAL_FLASH_Unlock();
|
||||
if (res_hal != HAL_OK)
|
||||
return res_hal;
|
||||
|
||||
res_hal = HAL_FLASH_OB_Unlock();
|
||||
if (res_hal != HAL_OK)
|
||||
return res_hal;
|
||||
|
||||
|
||||
FLASH->OPTCR |= FLASH_OPTCR_DB1M;
|
||||
|
||||
res_hal = HAL_FLASH_OB_Launch();
|
||||
if (res_hal != HAL_OK)
|
||||
return res_hal;
|
||||
|
||||
res_hal = HAL_FLASH_OB_Lock();
|
||||
if (res_hal != HAL_OK)
|
||||
return res_hal;
|
||||
|
||||
res_hal = HAL_FLASH_Lock();
|
||||
if (res_hal != HAL_OK)
|
||||
return res_hal;
|
||||
|
||||
|
||||
return res_hal;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Убрать защиту */
|
||||
HAL_StatusTypeDef FLASH_WriteProtection(uint32_t BankN, uint32_t WriteProtection)
|
||||
{
|
||||
HAL_StatusTypeDef res_hal;
|
||||
FLASH_OBProgramInitTypeDef OBInit;
|
||||
|
||||
// Очистка всех возможных ошибок
|
||||
FLASH->SR |= FLASH_FLAG_WRPERR // Write Protection Error
|
||||
| FLASH_FLAG_PGSERR // Programming Sequence Error
|
||||
| FLASH_FLAG_PGAERR // Programming Alignment Error
|
||||
| FLASH_FLAG_OPERR; // Operation Error
|
||||
|
||||
res_hal = HAL_FLASH_Unlock();
|
||||
if (res_hal != HAL_OK)
|
||||
return res_hal;
|
||||
|
||||
res_hal = HAL_FLASH_OB_Unlock(); // Разблокировка Option Bytes
|
||||
if (res_hal != HAL_OK)
|
||||
return res_hal;
|
||||
|
||||
// Считываем текущую конфигурацию Option Bytes
|
||||
HAL_FLASHEx_OBGetConfig(&OBInit);
|
||||
|
||||
// Отключаем защиту на всех секторах второго банка
|
||||
OBInit.OptionType = OPTIONBYTE_WRP;
|
||||
OBInit.WRPState = WriteProtection; // Снять защиту
|
||||
OBInit.WRPSector = OB_WRP_SECTOR_12; // Снять защиту
|
||||
OBInit.Banks = BankN; // Указываем второй банк
|
||||
res_hal = HAL_FLASHEx_OBProgram(&OBInit);
|
||||
if (res_hal != HAL_OK)
|
||||
return res_hal;
|
||||
|
||||
// Записываем изменения и перезагружаем чип
|
||||
res_hal = HAL_FLASH_OB_Launch();
|
||||
if (res_hal != HAL_OK)
|
||||
return res_hal;
|
||||
|
||||
// Считываем текущую конфигурацию Option Bytes
|
||||
HAL_FLASHEx_OBGetConfig(&OBInit);
|
||||
|
||||
// Блокировка Option Bytes
|
||||
res_hal = HAL_FLASH_OB_Lock();
|
||||
if (res_hal != HAL_OK)
|
||||
return res_hal;
|
||||
|
||||
res_hal = HAL_FLASH_Lock();
|
||||
if (res_hal != HAL_OK)
|
||||
return res_hal;
|
||||
|
||||
return res_hal;
|
||||
}
|
||||
//-----------------ELEMENTARY FUNCTIONS---------------------
|
||||
/* functions for reading bytes/halswords/words */
|
||||
uint8_t FLASH_Read_Byte(uint32_t add)
|
||||
{
|
||||
return (*(__IO uint8_t*)(add));
|
||||
}
|
||||
uint16_t FLASH_Read_HalfWord(uint32_t add)
|
||||
{
|
||||
return (*(__IO uint16_t*)(add));
|
||||
}
|
||||
uint32_t FLASH_Read_Word(uint32_t add)
|
||||
{
|
||||
return (*(__IO uint32_t*)(add));
|
||||
}
|
||||
/* functions for writing bytes/halswords/words */
|
||||
HAL_StatusTypeDef FLASH_Write_Byte(uint32_t Address, uint8_t Data)
|
||||
{
|
||||
HAL_StatusTypeDef res_hal;
|
||||
|
||||
res_hal = HAL_FLASH_Unlock();
|
||||
|
||||
if (res_hal != HAL_OK) return res_hal;
|
||||
|
||||
res_hal = HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, Address, (uint8_t)(Data));
|
||||
|
||||
if (res_hal != HAL_OK) return res_hal;
|
||||
|
||||
res_hal = HAL_FLASH_Lock();
|
||||
return res_hal;
|
||||
}
|
||||
HAL_StatusTypeDef FLASH_Write_HalfWord(uint32_t Address, uint16_t Data)
|
||||
{
|
||||
HAL_StatusTypeDef res_hal;
|
||||
|
||||
res_hal = HAL_FLASH_Unlock();
|
||||
|
||||
if (res_hal != HAL_OK) return res_hal;
|
||||
|
||||
res_hal = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, Address, (uint16_t)(Data));
|
||||
|
||||
if (res_hal != HAL_OK) return res_hal;
|
||||
|
||||
res_hal = HAL_FLASH_Lock();
|
||||
return res_hal;
|
||||
}
|
||||
HAL_StatusTypeDef FLASH_Write_Word(uint32_t Address, uint32_t Data)
|
||||
{
|
||||
HAL_StatusTypeDef res_hal;
|
||||
|
||||
res_hal = HAL_FLASH_Unlock();
|
||||
if (res_hal != HAL_OK) return res_hal;
|
||||
|
||||
res_hal = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address, (uint32_t)(Data));
|
||||
if (res_hal != HAL_OK) return res_hal;
|
||||
|
||||
res_hal = HAL_FLASH_Lock();
|
||||
return res_hal;
|
||||
}
|
||||
//----------------------------------------------------------
|
||||
|
||||
@@ -1,326 +0,0 @@
|
||||
/**
|
||||
**************************************************************************
|
||||
* @file general_gpio.c
|
||||
* @brief Модуль для инициализации портов и работы с ними.
|
||||
**************************************************************************
|
||||
* @details
|
||||
Реализация функций для работы с GPIO:
|
||||
- Включение тактирования портов
|
||||
- Инициализация светодиодов и кнопок
|
||||
- Управление светодиодами: включение, выключение, моргание, плавное затухание
|
||||
- Чтение состояния кнопок с фильтром от дребезга
|
||||
***************************************************************************/
|
||||
#include "general_gpio.h"
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
//------------------------GPIO INIT FUNCTIONS------------------------
|
||||
|
||||
|
||||
/**
|
||||
* @brief Включить тактирование порта GPIO
|
||||
*/
|
||||
HAL_StatusTypeDef GPIO_Clock_Enable(GPIO_TypeDef *GPIOx)
|
||||
{
|
||||
if(check_null_ptr_1(GPIOx))
|
||||
return HAL_ERROR;
|
||||
|
||||
HAL_StatusTypeDef status = HAL_OK;
|
||||
// choose port for enable clock
|
||||
if (GPIOx==GPIOA)
|
||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||
else if (GPIOx==GPIOB)
|
||||
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||||
#ifdef GPIOC
|
||||
else if (GPIOx==GPIOC)
|
||||
__HAL_RCC_GPIOC_CLK_ENABLE();
|
||||
#endif
|
||||
#ifdef GPIOD
|
||||
else if (GPIOx==GPIOD)
|
||||
__HAL_RCC_GPIOD_CLK_ENABLE();
|
||||
#endif
|
||||
#ifdef GPIOE
|
||||
else if (GPIOx==GPIOE)
|
||||
__HAL_RCC_GPIOE_CLK_ENABLE();
|
||||
#endif
|
||||
#ifdef GPIOF
|
||||
else if (GPIOx==GPIOF)
|
||||
__HAL_RCC_GPIOF_CLK_ENABLE();
|
||||
#endif
|
||||
#ifdef GPIOH
|
||||
else if (GPIOx==GPIOF)
|
||||
__HAL_RCC_GPIOH_CLK_ENABLE();
|
||||
#endif
|
||||
else
|
||||
status = HAL_ERROR;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//------------------------GPIO INIT FUNCTIONS------------------------
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
//------------------------GPIO LED FUNCTIONS-------------------------
|
||||
|
||||
/**
|
||||
* @brief Инициализировать светодиод (структуру светодиода)
|
||||
* @param led Указатель на структуру светодиода
|
||||
* @param GPIOx Указатель на структуру порта для светодиода
|
||||
* @param GPIO_PIN_X Пин для светодиода
|
||||
* @param LED_ActiveLevel Состояния пина, при котором светодиод будет включен
|
||||
*/
|
||||
HAL_StatusTypeDef GPIO_LED_Init(GPIO_LEDTypeDef *led, GPIO_TypeDef *GPIOx, uint32_t GPIO_PIN_X, uint8_t LED_ActiveLevel)
|
||||
{
|
||||
if(check_null_ptr_3(led, GPIOx, GPIO_PIN_X))
|
||||
return HAL_ERROR;
|
||||
|
||||
led->LED_Port = GPIOx;
|
||||
led->LED_Pin = GPIO_PIN_X;
|
||||
led->LED_ActiveLvl = LED_ActiveLevel;
|
||||
|
||||
GPIO_LED_Off(led);
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Включить светодиод
|
||||
* @param led Указатель на структуру светодиода
|
||||
* @return HAL Status
|
||||
*/
|
||||
HAL_StatusTypeDef GPIO_LED_On(GPIO_LEDTypeDef *led)
|
||||
{
|
||||
if(check_null_ptr_3(led, led->LED_Port, led->LED_Pin))
|
||||
return HAL_ERROR;
|
||||
|
||||
led->state = LED_IS_ON;
|
||||
HAL_GPIO_WritePin(led->LED_Port, led->LED_Pin, led->LED_ActiveLvl);
|
||||
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
/**
|
||||
* @brief Выключить светодиод
|
||||
* @param led Указатель на структуру светодиода
|
||||
* @return HAL Status
|
||||
*/
|
||||
HAL_StatusTypeDef GPIO_LED_Off(GPIO_LEDTypeDef *led)
|
||||
{
|
||||
if(check_null_ptr_3(led, led->LED_Port, led->LED_Pin))
|
||||
return HAL_ERROR;
|
||||
|
||||
led->state = LED_IS_OFF;
|
||||
HAL_GPIO_WritePin(led->LED_Port, led->LED_Pin, !led->LED_ActiveLvl);
|
||||
|
||||
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
/**
|
||||
* @brief Выставить светодиод по переменной
|
||||
* @param led Указатель на структуру светодиода
|
||||
* @param led_state Состояние светодиода
|
||||
* @return HAL Status
|
||||
*/
|
||||
HAL_StatusTypeDef GPIO_LED_Set(GPIO_LEDTypeDef *led, uint8_t led_state)
|
||||
{
|
||||
if(check_null_ptr_3(led, led->LED_Port, led->LED_Pin))
|
||||
return HAL_ERROR;
|
||||
|
||||
if(led_state)
|
||||
{
|
||||
return GPIO_LED_On(led);
|
||||
}
|
||||
else
|
||||
{
|
||||
return GPIO_LED_Off(led);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief Активировать моргание светодиодом
|
||||
* @param led Указатель на структуру светодиода
|
||||
* @param period Период плавного моргания светодиода
|
||||
* @return HAL Status
|
||||
* @details Функция ставит режим моргания, который после управляется в @ref GPIO_LED_Dynamic_Handle
|
||||
*/
|
||||
HAL_StatusTypeDef GPIO_LED_Blink_Start(GPIO_LEDTypeDef *led, uint32_t period)
|
||||
{
|
||||
if(check_null_ptr_3(led, led->LED_Port, led->LED_Pin))
|
||||
return HAL_ERROR;
|
||||
|
||||
led->state = LED_IS_BLINKING;
|
||||
led->LED_Period = period;
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Активировать моргание светодиодом
|
||||
* @param led Указатель на структуру светодиода
|
||||
* @param period Период плавного моргания светодиода
|
||||
* @return HAL Status
|
||||
* @details Функция ставит режим моргания, который после управляется в @ref GPIO_LED_Dynamic_Handle
|
||||
*/
|
||||
HAL_StatusTypeDef GPIO_LED_Fading_Start(GPIO_LEDTypeDef *led, uint32_t period)
|
||||
{
|
||||
if(check_null_ptr_3(led, led->LED_Port, led->LED_Pin))
|
||||
return HAL_ERROR;
|
||||
|
||||
led->state = LED_IS_FADING;
|
||||
led->LED_Period = period;
|
||||
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
//uint8_t LED_PWM_FADING_DUTYS[LED_PWM_TICKS] = {0 1 2 3 4 5 6 7 8 9 10 11 12 }
|
||||
/**
|
||||
* @brief Управление динамическими режимами свечения светодиода
|
||||
* @param Указатель на структуру светодиода
|
||||
* @details Функция моргает/плавно моргает светодиодом в неблокирующем режиме
|
||||
* Т.е. функцию надо вызывать постоянно, чтобы она мониторила тики
|
||||
* и в нужный момент переключала светодиод
|
||||
*/
|
||||
void GPIO_LED_Dynamic_Handle(GPIO_LEDTypeDef *led)
|
||||
{
|
||||
if(check_null_ptr_3(led, led->LED_Port, led->LED_Pin))
|
||||
return;
|
||||
|
||||
/* Режим моргания светодиода */
|
||||
if(led->state == LED_IS_BLINKING)
|
||||
{
|
||||
uint32_t tickcurrent = local_time();
|
||||
/* Ожидание истечения периода моргания */
|
||||
if((tickcurrent - led->tickprev) > led->LED_Period)
|
||||
{
|
||||
/* Моргание */
|
||||
HAL_GPIO_TogglePin(led->LED_Port, led->LED_Pin);
|
||||
|
||||
led->tickprev = tickcurrent;
|
||||
}
|
||||
}
|
||||
/* Режим плавного моргания светодиода */
|
||||
else if(led->state == LED_IS_FADING)
|
||||
{
|
||||
static unsigned direction = 0;
|
||||
static int duty = 0;
|
||||
uint32_t tickcurrent = local_time();
|
||||
/* Ожидание момента изменения яркости */
|
||||
/* Период ШИМ 20 мс, поэтому менять яроксть надо 40 раз за период (туда обратно) */
|
||||
if((tickcurrent - led->tickprev) > led->LED_Period/(LED_PWM_TICKS*2))
|
||||
{
|
||||
/* Формирование разтухания */
|
||||
if(direction == 0)
|
||||
{
|
||||
if(++duty >= LED_PWM_TICKS)
|
||||
{
|
||||
direction = 1;
|
||||
duty = LED_PWM_TICKS;
|
||||
}
|
||||
}
|
||||
/* Формирование затухания */
|
||||
else
|
||||
{
|
||||
if(--duty <= 0)
|
||||
{
|
||||
direction = 0;
|
||||
duty = 0;
|
||||
}
|
||||
}
|
||||
led->tickprev = tickcurrent;
|
||||
}
|
||||
/* Формирование ШИМ для изменения яркости */
|
||||
int duty_crt = (duty*duty/LED_PWM_TICKS);
|
||||
if(tickcurrent%LED_PWM_TICKS < duty_crt)
|
||||
{
|
||||
HAL_GPIO_WritePin(led->LED_Port, led->LED_Pin, led->LED_ActiveLvl);
|
||||
}
|
||||
else
|
||||
{
|
||||
HAL_GPIO_WritePin(led->LED_Port, led->LED_Pin, !led->LED_ActiveLvl);
|
||||
}
|
||||
}
|
||||
}
|
||||
//------------------------GPIO LED FUNCTIONS-------------------------
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
//------------------------GPIO SW FUNCTIONS-------------------------
|
||||
|
||||
/**
|
||||
* @brief Инициализировать кнопку (структуру кнопки)
|
||||
* @param sw Указатель на структуру кнопки
|
||||
* @param GPIOx Указатель на структуру порта для кнопки
|
||||
* @param GPIO_PIN_X Пин для кнопки
|
||||
* @param SW_ActiveLevel Состояния пина, когда кнопка нажата
|
||||
* @return HAL Status
|
||||
*/
|
||||
HAL_StatusTypeDef GPIO_Switch_Init(GPIO_SwitchTypeDef *sw, GPIO_TypeDef *GPIOx, uint32_t GPIO_PIN_X, uint8_t SW_ActiveLevel)
|
||||
{
|
||||
if(check_null_ptr_3(sw, GPIOx, GPIO_PIN_X))
|
||||
return HAL_ERROR;
|
||||
|
||||
sw->Sw_Port = GPIOx;
|
||||
sw->Sw_Pin = GPIO_PIN_X;
|
||||
sw->Sw_ActiveLvl = SW_ActiveLevel;
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Считать состоянии кнопки
|
||||
* @param sw Указатель на структуру кнопки
|
||||
* @return 1 - если кнопка нажата,
|
||||
* 0 - если отжата,
|
||||
* -1 - если ошибка
|
||||
* @details Функция включает в себя неблокирующую проверку на дребезг
|
||||
* Т.е. функцию надо вызывать постоянно, чтобы она мониторила состояние кнопки
|
||||
*/
|
||||
int GPIO_Read_Switch(GPIO_SwitchTypeDef *sw)
|
||||
{
|
||||
if(check_null_ptr_3(sw, sw->Sw_Port, sw->Sw_Pin))
|
||||
return -1;
|
||||
|
||||
if(HAL_GPIO_ReadPin(sw->Sw_Port, sw->Sw_Pin) == sw->Sw_ActiveLvl)
|
||||
{
|
||||
sw->Sw_PrevState = 1;
|
||||
|
||||
|
||||
if(sw->Sw_FilterDelay) // если включена защита от дребезга
|
||||
{
|
||||
if(sw->tickprev == 0)
|
||||
sw->tickprev = local_time();
|
||||
|
||||
if((local_time() - sw->tickprev) >= sw->Sw_FilterDelay)
|
||||
{
|
||||
if(HAL_GPIO_ReadPin(sw->Sw_Port, sw->Sw_Pin) == sw->Sw_ActiveLvl)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
sw->tickprev = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // если нет защиты от дребезга
|
||||
{
|
||||
if(HAL_GPIO_ReadPin(sw->Sw_Port, sw->Sw_Pin) == sw->Sw_ActiveLvl)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
sw->tickprev = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sw->Sw_PrevState = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
//------------------------GPIO SW FUNCTIONS-------------------------
|
||||
//-------------------------------------------------------------------
|
||||
@@ -1,284 +0,0 @@
|
||||
/**
|
||||
**************************************************************************
|
||||
* @file general_spi.c
|
||||
* @brief Модуль для инициализации SPI.
|
||||
**************************************************************************
|
||||
Реализация функций для работы с SPI:
|
||||
- Инициализация SPI и его линий CLK/MISO/MOSI
|
||||
- Настройка GPIO для SPI
|
||||
- Настройка NVIC и тактирования SPI
|
||||
**************************************************************************/
|
||||
#include "general_spi.h"
|
||||
#include "general_gpio.h"
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
//------------------------SPI INIT FUNCTIONS------------------------
|
||||
/**
|
||||
* @brief Инициализация SPI с помощью структуры SPI_SettingsTypeDef.
|
||||
* @param sspi Указатель на структуру с настройками SPI.
|
||||
* @return HAL status.
|
||||
* @details
|
||||
* Инициализирует SPI и его GPIO.
|
||||
* Настройка аналогична HAL_SPI_Init
|
||||
* @code
|
||||
* suart.hspi.Init...
|
||||
* @endcode
|
||||
* но дополнительно надо прописать пины CLK/MISO/MOSI @ref SPI_SettingsTypeDef
|
||||
*/
|
||||
HAL_StatusTypeDef SPI_Base_Init(SPI_SettingsTypeDef *sspi)
|
||||
{ // function takes setting structure for init
|
||||
|
||||
// check is settings are valid
|
||||
if(SPI_Check_Init_Struct(sspi) != HAL_OK)
|
||||
return HAL_ERROR;
|
||||
|
||||
SPI_MspInit(&sspi->hspi);
|
||||
|
||||
if (HAL_SPI_Init(&sspi->hspi) != HAL_OK)
|
||||
{
|
||||
MyLibs_Error_Handler();
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
// init gpio from SPISettings structure
|
||||
SPI_GPIO_Init(sspi);
|
||||
|
||||
// // init dma from SPISettings structure if need
|
||||
// if (sspi->DMAChannel != 0)
|
||||
// SPI_DMA_Init(&sspi->hspi, sspi->hspi.hdmarx, sspi->DMAChannel, sspi->DMA_CHANNEL_X);
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Инициализация GPIO для SPI.
|
||||
* @param sspi Указатель на структуру с настройками SPI.
|
||||
*/
|
||||
void SPI_GPIO_Init(SPI_SettingsTypeDef *sspi)
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
// GPIO INIT
|
||||
GPIO_Clock_Enable(sspi->CLK_GPIOx);
|
||||
GPIO_Clock_Enable(sspi->MISO_GPIOx);
|
||||
GPIO_Clock_Enable(sspi->MOSI_GPIOx);
|
||||
// CLK PIN INIT
|
||||
GPIO_InitStruct.Pin = sspi->CLK_PIN;
|
||||
GPIO_InitStruct.Alternate = sspi->CLK_GPIO_AlternageFunc;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
||||
HAL_GPIO_Init(sspi->CLK_GPIOx, &GPIO_InitStruct);
|
||||
// MISO PIN INIT
|
||||
GPIO_InitStruct.Pin = sspi->MISO_PIN;
|
||||
GPIO_InitStruct.Alternate = sspi->MISO_GPIO_AlternageFunc;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
||||
HAL_GPIO_Init(sspi->MISO_GPIOx, &GPIO_InitStruct);
|
||||
// MOSI PIN INIT
|
||||
GPIO_InitStruct.Pin = sspi->MOSI_PIN;
|
||||
GPIO_InitStruct.Alternate = sspi->MOSI_GPIO_AlternageFunc;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
||||
HAL_GPIO_Init(sspi->MOSI_GPIOx, &GPIO_InitStruct);
|
||||
}
|
||||
|
||||
|
||||
void SPI_DMA_Init(SPI_HandleTypeDef *hspi, DMA_HandleTypeDef *hdma_rx, DMA_Stream_TypeDef *DMAChannel, uint32_t DMA_CHANNEL_X)
|
||||
{ // function takes spi and dma handlers and dmachannel for spi
|
||||
// // for now only dma rx is supported, tx maybe later if needed
|
||||
// // calc defines on boot_project_setup.h
|
||||
|
||||
// /* SPI3 DMA Init */
|
||||
// /* SPI3_RX Init */
|
||||
//
|
||||
// hdma_rx->Instance = DMAChannel;
|
||||
//#if defined(STM32F4xx) // dma channel choose for 407
|
||||
// hdma_rx->Init.Channel = DMA_CHANNEL_X;
|
||||
//#endif
|
||||
// hdma_rx->Init.Direction = DMA_PERIPH_TO_MEMORY;
|
||||
// hdma_rx->Init.PeriphInc = DMA_PINC_DISABLE;
|
||||
// hdma_rx->Init.MemInc = DMA_MINC_ENABLE;
|
||||
// hdma_rx->Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
|
||||
// hdma_rx->Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
|
||||
// hdma_rx->Init.Mode = DMA_CIRCULAR;
|
||||
// hdma_rx->Init.Priority = DMA_PRIORITY_LOW;
|
||||
// if (HAL_DMA_Init(hdma_rx) != HAL_OK)
|
||||
// {
|
||||
// MyLibs_Error_Handler();
|
||||
// }
|
||||
|
||||
// __USER_LINKDMA(hspi,hdmarx,hdma_rx);
|
||||
//
|
||||
|
||||
// // __USER_LINKDMA is need because __HAL_LINKDMA is written for global defined hdma_rx
|
||||
// // so you get error because hal uses . insted of ->
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Настройка тактирования и прерываний SPI.
|
||||
* @param hspi Указатель на хендл SPI.
|
||||
* @note Чтобы не генерировать функцию с иницилизацией неиспользуемых SPI,
|
||||
дефайнами @ref SPI_INIT в @ref general_spi.h определяются используемые SPI.
|
||||
*/
|
||||
void SPI_MspInit(SPI_HandleTypeDef *hspi) // analog for hal function
|
||||
{
|
||||
// rcc, dma and interrupt init for SPIs
|
||||
// GPIO init was moved to own functions SPI_GPIO_Init
|
||||
if(0);
|
||||
#ifdef USE_SPI1
|
||||
else if(hspi->Instance==SPI1)
|
||||
{
|
||||
|
||||
// /* DMA2 clock enable */
|
||||
// __HAL_RCC_DMA2_CLK_ENABLE();
|
||||
// /* DMA interrupt init */
|
||||
// HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 0, 0);
|
||||
// HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
|
||||
|
||||
/* SPI1 clock enable */
|
||||
__HAL_RCC_SPI1_CLK_ENABLE();
|
||||
|
||||
/* SPI1 interrupt Init */
|
||||
HAL_NVIC_SetPriority(SPI1_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(SPI1_IRQn);
|
||||
}
|
||||
#endif // USE_SPI1
|
||||
#ifdef USE_SPI2
|
||||
else if(hspi->Instance==SPI2)
|
||||
{
|
||||
// /* DMA1 clock enable */
|
||||
// __HAL_RCC_DMA1_CLK_ENABLE();
|
||||
// /* DMA interrupt init */
|
||||
// HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 0, 0);
|
||||
// HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);
|
||||
|
||||
/* SPI2 clock enable */
|
||||
__HAL_RCC_SPI2_CLK_ENABLE();
|
||||
|
||||
/* SPI2 interrupt Init */
|
||||
HAL_NVIC_SetPriority(SPI2_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(SPI2_IRQn);
|
||||
}
|
||||
#endif // USE_SPI2
|
||||
#ifdef USE_SPI3
|
||||
else if(hspi->Instance==SPI3)
|
||||
{
|
||||
// /* DMA1 clock enable */
|
||||
// __HAL_RCC_DMA1_CLK_ENABLE();
|
||||
// /* DMA interrupt init */
|
||||
// HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0);
|
||||
// HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
|
||||
|
||||
/* SPI3 clock enable */
|
||||
__HAL_RCC_SPI3_CLK_ENABLE();
|
||||
/* SPI3 interrupt Init */
|
||||
HAL_NVIC_SetPriority(SPI3_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(SPI3_IRQn);
|
||||
}
|
||||
#endif // USE_SPI3
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Деинициализация тактирования и прерываний SPI.
|
||||
* @param hspi Указатель на хендл SPI.
|
||||
* @note Чтобы не генерировать функцию с иницилизацией неиспользуемых SPI,
|
||||
дефайнами @ref SPI_INIT в @ref general_spi.h определяются используемые SPI.
|
||||
*/
|
||||
void SPI_MspDeInit(SPI_HandleTypeDef *hspi) // analog for hal function
|
||||
{
|
||||
// rcc, dma and interrupt init for SPIs
|
||||
// GPIO init was moved to own functions SPI_GPIO_Init
|
||||
if(0);
|
||||
#ifdef USE_SPI1
|
||||
else if(hspi->Instance==SPI1)
|
||||
{
|
||||
|
||||
// /* DMA2 clock enable */
|
||||
// __HAL_RCC_DMA2_CLK_ENABLE();
|
||||
// /* DMA interrupt init */
|
||||
// HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 0, 0);
|
||||
// HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
|
||||
|
||||
/* SPI1 clock reset */
|
||||
__HAL_RCC_SPI1_FORCE_RESET();
|
||||
__HAL_RCC_SPI1_RELEASE_RESET();
|
||||
}
|
||||
#endif // USE_SPI1
|
||||
#ifdef USE_SPI2
|
||||
else if(hspi->Instance==SPI2)
|
||||
{
|
||||
// /* DMA1 clock enable */
|
||||
// __HAL_RCC_DMA1_CLK_ENABLE();
|
||||
// /* DMA interrupt init */
|
||||
// HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 0, 0);
|
||||
// HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);
|
||||
|
||||
/* SPI2 clock reset */
|
||||
__HAL_RCC_SPI2_FORCE_RESET();
|
||||
__HAL_RCC_SPI2_RELEASE_RESET();
|
||||
}
|
||||
#endif // USE_SPI2
|
||||
#ifdef USE_SPI3
|
||||
else if(hspi->Instance==SPI3)
|
||||
{
|
||||
// /* DMA1 clock enable */
|
||||
// __HAL_RCC_DMA1_CLK_ENABLE();
|
||||
// /* DMA interrupt init */
|
||||
// HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0);
|
||||
// HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
|
||||
|
||||
/* SPI3 clock reset */
|
||||
__HAL_RCC_SPI3_FORCE_RESET();
|
||||
__HAL_RCC_SPI3_RELEASE_RESET();
|
||||
}
|
||||
#endif // USE_SPI3
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Проверка корректности структуры инициализации SPI.
|
||||
* @param sspi Указатель на структуру с настройками SPI.
|
||||
* @return HAL status.
|
||||
*/
|
||||
HAL_StatusTypeDef SPI_Check_Init_Struct(SPI_SettingsTypeDef *sspi)
|
||||
{
|
||||
// check is settings are valid
|
||||
if (!IS_SPI_ALL_INSTANCE(sspi->hspi.Instance))
|
||||
return HAL_ERROR;
|
||||
|
||||
// check init settings
|
||||
if (!IS_SPI_MODE(sspi->hspi.Init.Mode))
|
||||
return HAL_ERROR;
|
||||
if (!IS_SPI_DIRECTION(sspi->hspi.Init.Direction))
|
||||
return HAL_ERROR;
|
||||
if (!IS_SPI_DATASIZE(sspi->hspi.Init.DataSize))
|
||||
return HAL_ERROR;
|
||||
if (!IS_SPI_BAUDRATE_PRESCALER(sspi->hspi.Init.BaudRatePrescaler))
|
||||
return HAL_ERROR;
|
||||
if (!IS_SPI_CPOL(sspi->hspi.Init.CLKPolarity))
|
||||
return HAL_ERROR;
|
||||
if (!IS_SPI_CPHA(sspi->hspi.Init.CLKPhase))
|
||||
return HAL_ERROR;
|
||||
if (!IS_SPI_NSS(sspi->hspi.Init.NSS))
|
||||
return HAL_ERROR;
|
||||
if (!IS_SPI_FIRST_BIT(sspi->hspi.Init.FirstBit))
|
||||
return HAL_ERROR;
|
||||
if (!IS_SPI_CRC_CALCULATION(sspi->hspi.Init.CRCCalculation))
|
||||
return HAL_ERROR;
|
||||
if (!IS_SPI_CRC_POLYNOMIAL(sspi->hspi.Init.NSS) &&
|
||||
(sspi->hspi.Init.CRCCalculation != SPI_CRCCALCULATION_DISABLE))
|
||||
return HAL_ERROR;
|
||||
if (!IS_SPI_TIMODE(sspi->hspi.Init.TIMode))
|
||||
return HAL_ERROR;
|
||||
|
||||
// check gpio
|
||||
if (!IS_GPIO_ALL_INSTANCE(sspi->CLK_GPIOx) || !IS_GPIO_ALL_INSTANCE(sspi->MISO_GPIOx) || !IS_GPIO_ALL_INSTANCE(sspi->MOSI_GPIOx))
|
||||
return HAL_ERROR;
|
||||
if (!IS_GPIO_PIN(sspi->CLK_PIN) && !IS_GPIO_PIN(sspi->MISO_PIN) && !IS_GPIO_PIN(sspi->MOSI_PIN)) // if both pins arent set up
|
||||
return HAL_ERROR;
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
@@ -1,722 +0,0 @@
|
||||
/**
|
||||
**************************************************************************
|
||||
* @file general_tim.c
|
||||
* @brief Модуль для инициализации таймеров и работы с ними.
|
||||
**************************************************************************
|
||||
Реализация функций для работы с TIM:
|
||||
- Инициализация таймера и его каналов
|
||||
- Формирование задержек через таймеры
|
||||
- Считывание энкодера
|
||||
*************************************************************************/
|
||||
#include "general_tim.h"
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
//-------------------------TIM INIT FUNCTIONS------------------------
|
||||
/**
|
||||
* @brief Инициализация таймера.
|
||||
* @param stim Указатель на структуру с настройками таймера.
|
||||
* @return HAL status.
|
||||
* @details
|
||||
* Инициализирует таймер исходя из настроек верхнего уровня:
|
||||
* - Длительность одного тика @ref TIM_MHzTickBaseTypeDef
|
||||
* - Частота таймера (в Гц, float)
|
||||
* - Частота тактирования таймера от шины (в Гц, float)
|
||||
*
|
||||
* При невозможности выставления частоты при заданой длительности тика
|
||||
* длительность тика увеличивается до тех пор, пока частота не будет достигнута.
|
||||
*
|
||||
* При выставлении дефайна @ref UPDATE_TIM_PARAMS_AFTER_INITIALIZATION
|
||||
* новая длительность тика записывается в структуру.
|
||||
*
|
||||
* Также остается возможность низкоуровневой настройки по структурам @ref TIM_SettingsTypeDef.
|
||||
* Для этого надо высокоуровневые настройки приравнять к нулю
|
||||
*/
|
||||
HAL_StatusTypeDef TIM_Base_Init(TIM_SettingsTypeDef *stim)
|
||||
{ // function takes structure for init
|
||||
// check that htim is defined
|
||||
if(check_null_ptr_2(stim, stim->htim.Instance))
|
||||
return HAL_ERROR;
|
||||
|
||||
|
||||
|
||||
if(stim->sTickBaseUS) // if tickbase isnt disable
|
||||
{
|
||||
if(stim->sTimAHBFreqMHz == NULL)
|
||||
return HAL_ERROR;
|
||||
stim->htim.Init.Prescaler = (stim->sTimAHBFreqMHz*stim->sTickBaseUS) - 1;
|
||||
|
||||
if ((stim->sTimFreqHz != NULL))
|
||||
stim->htim.Init.Period = ((1000000/stim->sTickBaseUS) / stim->sTimFreqHz) - 1;
|
||||
else if (stim->htim.Init.Period == NULL)
|
||||
stim->htim.Init.Period = 0xFFFF;
|
||||
|
||||
if(stim->sTickBasePrescaler)
|
||||
{
|
||||
stim->htim.Init.Prescaler = (stim->htim.Init.Prescaler + 1)/stim->sTickBasePrescaler - 1;
|
||||
stim->htim.Init.Period = (stim->htim.Init.Period + 1)*stim->sTickBasePrescaler - 1;
|
||||
}
|
||||
else
|
||||
stim->sTickBasePrescaler = 1;
|
||||
}
|
||||
|
||||
// fix overflow of presc and period if need
|
||||
for(int i = 0; (stim->htim.Init.Prescaler > 0xFFFF) || (stim->htim.Init.Period > 0xFFFF); i++)
|
||||
{
|
||||
if (i>10) // if it isnt fixed after 10 itteration - return HAL_ERRPOR
|
||||
{
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
// if timbase is too big (prescaller too big for choosen base from MHZ)
|
||||
if(stim->htim.Init.Prescaler > 0xFFFF)
|
||||
{
|
||||
// переносим часть пресскалера в период
|
||||
stim->htim.Init.Prescaler = ((stim->htim.Init.Prescaler + 1)/2) - 1;
|
||||
stim->htim.Init.Period = ((stim->htim.Init.Period + 1)*2) - 1;
|
||||
// обновляем TickBase, если есть куда обновлять
|
||||
if(stim->sTickBaseUS > 1)
|
||||
stim->sTickBaseUS /= 2;
|
||||
// обновляем sTickBasePrescaler, если sTickBaseUS - уже в минимуме
|
||||
else if (stim->sTickBaseUS == 1)
|
||||
stim->sTickBasePrescaler *= 2;
|
||||
else // if TickBase = 0 - return error
|
||||
return HAL_ERROR;
|
||||
}
|
||||
// if freq is too low (period too big for choosen base)
|
||||
if(stim->htim.Init.Period > 0xFFFF)
|
||||
{
|
||||
// переносим часть периода в прескалер
|
||||
stim->htim.Init.Period = ((stim->htim.Init.Period + 1)/2) - 1;
|
||||
stim->htim.Init.Prescaler = ((stim->htim.Init.Prescaler + 1)*2) - 1;
|
||||
// обновляем TickBase
|
||||
stim->sTickBaseUS *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------TIM BASE INIT----------------
|
||||
// tim base init
|
||||
TIM_Base_MspInit(&stim->htim, stim->sTimMode);
|
||||
if (HAL_TIM_Base_Init(&stim->htim) != HAL_OK)
|
||||
{
|
||||
MyLibs_Error_Handler();
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
//-------------CLOCK SRC INIT---------------
|
||||
// fill sClockSourceConfig if its NULL
|
||||
if (stim->sClockSourceConfig.ClockSource == NULL)
|
||||
stim->sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
|
||||
// clock source init
|
||||
if (HAL_TIM_ConfigClockSource(&stim->htim, &stim->sClockSourceConfig) != HAL_OK)
|
||||
{
|
||||
MyLibs_Error_Handler();
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
//--------------SLAVE INIT------------------
|
||||
// if slave mode enables - config it
|
||||
if (stim->sSlaveConfig.SlaveMode)
|
||||
{
|
||||
// slave mode init
|
||||
if (HAL_TIM_SlaveConfigSynchro(&stim->htim, &stim->sSlaveConfig) != HAL_OK)
|
||||
{
|
||||
MyLibs_Error_Handler();
|
||||
return HAL_ERROR;
|
||||
}
|
||||
}
|
||||
//--------------MASTER INIT-----------------
|
||||
// master mode init
|
||||
if (HAL_TIMEx_MasterConfigSynchronization(&stim->htim, &stim->sMasterConfig) != HAL_OK)
|
||||
{
|
||||
MyLibs_Error_Handler();
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
//--------------BDTR INIT-----------------
|
||||
if (HAL_TIMEx_ConfigBreakDeadTime(&stim->htim, &stim->sBreakDeadTimeConfig) != HAL_OK)
|
||||
{
|
||||
MyLibs_Error_Handler();
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
//----------------IT CLEAR-------------------
|
||||
__HAL_TIM_CLEAR_IT(&stim->htim, TIM_IT_UPDATE);
|
||||
|
||||
|
||||
// обновляем TickBase
|
||||
#ifdef UPDATE_TIM_PARAMS_AFTER_INITIALIZATION
|
||||
stim->sTickBaseUS = (stim->htim.Instance->PSC+1)*stim->sTickBasePrescaler/(stim->sTimAHBFreqMHz);
|
||||
if(stim->sTickBaseUS == 0) // if prescaler is too high
|
||||
{ // recalc what is prescaler irl
|
||||
stim->sTickBaseUS = 1;
|
||||
stim->sTickBasePrescaler = stim->sTimAHBFreqMHz/(stim->htim.Instance->PSC+1);
|
||||
}
|
||||
#endif
|
||||
stim->htim.Instance->CNT = 0;
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Инициализация режима энкодер у таймера.
|
||||
* @param henc Указатель на хендл энкодера.
|
||||
* @param htim Указатель на хендл таймера.
|
||||
* @return HAL status.
|
||||
* @note Предварительно надо инициализировать таймер @ref TIM_Base_Init.
|
||||
*/
|
||||
HAL_StatusTypeDef TIM_Encoder_Init(TIM_EncoderTypeDef *henc, TIM_HandleTypeDef *htim)
|
||||
{
|
||||
if(check_null_ptr_3(henc, htim, htim->Instance))
|
||||
return HAL_ERROR;
|
||||
if(check_null_ptr_3(henc->GPIOx, henc->GPIO_PIN_TI1, henc->GPIO_PIN_TI2))
|
||||
return HAL_ERROR;
|
||||
|
||||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
HAL_StatusTypeDef RES = HAL_ERROR;
|
||||
henc->htim = htim;
|
||||
|
||||
// setup channel for pwm
|
||||
RES = HAL_TIM_Encoder_Init(henc->htim, &henc->sConfig);
|
||||
if (RES != HAL_OK)
|
||||
{
|
||||
MyLibs_Error_Handler();
|
||||
return RES;
|
||||
}
|
||||
// choose port for enable clock
|
||||
RES = GPIO_Clock_Enable(henc->GPIOx);
|
||||
if(RES != HAL_OK)
|
||||
{
|
||||
MyLibs_Error_Handler();
|
||||
return RES;
|
||||
}
|
||||
|
||||
GPIO_InitStruct.Pin = henc->GPIO_PIN_TI1|henc->GPIO_PIN_TI2;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_PULLUP;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStruct.Alternate = GPIO_TIM_Alternate_Mapping(henc->htim->Instance);
|
||||
if(GPIO_InitStruct.Alternate)
|
||||
HAL_GPIO_Init(henc->GPIOx, &GPIO_InitStruct);
|
||||
|
||||
if(henc->GPIO_PIN_SW)
|
||||
{
|
||||
/*Configure switch pin */
|
||||
GPIO_InitStruct.Pin = henc->GPIO_PIN_SW;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
|
||||
GPIO_InitStruct.Pull = GPIO_PULLUP;
|
||||
HAL_GPIO_Init(henc->GPIOx, &GPIO_InitStruct);
|
||||
|
||||
GPIO_Switch_Init(&henc->Sw, henc->GPIOx, henc->GPIO_PIN_SW, 0);
|
||||
}
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Инициализация выхода ШИМ таймера.
|
||||
* @param htim Указатель на хендл таймера.
|
||||
* @param sConfigOC Указатель на настрйоки канала таймера.
|
||||
* @param TIM_CHANNEL Канал таймера для настройки.
|
||||
* @param GPIOx Порт для вывода ШИМ.
|
||||
* @param GPIO_PIN Пин для вывода ШИМ.
|
||||
* @return HAL status.
|
||||
* @note Предварительно надо инициализировать таймер @ref TIM_Base_Init.
|
||||
*/
|
||||
HAL_StatusTypeDef TIM_Output_PWM_Init(TIM_HandleTypeDef *htim, TIM_OC_InitTypeDef *sConfigOC, uint32_t TIM_CHANNEL, GPIO_TypeDef *GPIOx, uint32_t GPIO_PIN)
|
||||
{
|
||||
if(check_null_ptr_3(htim, htim->Instance, sConfigOC))
|
||||
return HAL_ERROR;
|
||||
if(check_null_ptr_2(GPIOx, GPIO_PIN))
|
||||
return HAL_ERROR;
|
||||
|
||||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
HAL_StatusTypeDef RES = HAL_ERROR;
|
||||
|
||||
// setup channel for pwm
|
||||
RES = HAL_TIM_PWM_ConfigChannel(htim, sConfigOC, TIM_CHANNEL);
|
||||
if (RES != HAL_OK)
|
||||
{
|
||||
MyLibs_Error_Handler();
|
||||
return RES;
|
||||
}
|
||||
// choose port for enable clock
|
||||
RES = GPIO_Clock_Enable(GPIOx);
|
||||
if(RES != HAL_OK)
|
||||
{
|
||||
MyLibs_Error_Handler();
|
||||
return RES;
|
||||
}
|
||||
|
||||
GPIO_InitStruct.Pin = GPIO_PIN;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
if(sConfigOC->OCPolarity == TIM_OCNPOLARITY_HIGH)
|
||||
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
|
||||
else
|
||||
GPIO_InitStruct.Pull = GPIO_PULLUP;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStruct.Alternate = GPIO_TIM_Alternate_Mapping(htim->Instance);
|
||||
if(GPIO_InitStruct.Alternate)
|
||||
HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Инициализация OC компаратора таймера.
|
||||
* @param htim Указатель на хендл таймера.
|
||||
* @param TIM_CHANNEL Канал таймера для настройки.
|
||||
* @return HAL status.
|
||||
* @note Предварительно надо инициализировать таймер @ref TIM_Base_Init.
|
||||
*/
|
||||
HAL_StatusTypeDef TIM_OC_Comparator_Init(TIM_HandleTypeDef *htim, uint32_t TIM_CHANNEL)
|
||||
{
|
||||
if(check_null_ptr_2(htim, htim->Instance))
|
||||
return HAL_ERROR;
|
||||
|
||||
TIM_OC_InitTypeDef sConfigOC = {0};
|
||||
HAL_StatusTypeDef RES = HAL_ERROR;
|
||||
|
||||
sConfigOC.OCMode = TIM_OCMODE_ACTIVE;
|
||||
sConfigOC.Pulse = 0;
|
||||
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
|
||||
|
||||
RES = HAL_TIM_OC_ConfigChannel(htim, &sConfigOC, TIM_CHANNEL);
|
||||
if (RES != HAL_OK)
|
||||
{
|
||||
MyLibs_Error_Handler();
|
||||
return RES;
|
||||
}
|
||||
return RES;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
//-------------------------TIM USER FUNCTIONS------------------------
|
||||
/**
|
||||
* @brief Считать энкодер.
|
||||
* @param henc Указатель на хендл энкодера.
|
||||
* @return HAL status.
|
||||
* @details Читает разницу энкодера, которую он накопил после
|
||||
* предыдущего вызова этой функции.
|
||||
*/
|
||||
HAL_StatusTypeDef TIM_Encoder_Read(TIM_EncoderTypeDef *henc)
|
||||
{
|
||||
if(check_null_ptr_3(henc, henc->htim, henc->htim->Instance))
|
||||
return HAL_ERROR;
|
||||
|
||||
uint16_t cnt_now = (uint16_t)henc->htim->Instance->CNT;
|
||||
int16_t diff = (int16_t)(cnt_now - henc->Encoder_Shdw); // переполнение корректно обрабатывается
|
||||
henc->Encoder_Diff = diff;
|
||||
henc->Encoder_Shdw = cnt_now;
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
/**
|
||||
* @brief Считать кнопку энкодера.
|
||||
* @param henc Указатель на хендл энкодера.
|
||||
* @return 1 - если кнопка нажата,
|
||||
* 0 - если отжата,
|
||||
* -1 - если ошибка
|
||||
*/
|
||||
int TIM_Encoder_ReadSwitch(TIM_EncoderTypeDef *henc)
|
||||
{
|
||||
if(check_null_ptr_1(henc))
|
||||
return -1;
|
||||
|
||||
return GPIO_Read_Switch(&henc->Sw);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Задержка в тиках таймера (блокирующая).
|
||||
* @param htim Указатель на хендл таймера.
|
||||
* @param delay Задержка в тиках таймера.
|
||||
* @return HAL status.
|
||||
* @details Формирует задержку с блокировкой программы.
|
||||
*/
|
||||
HAL_StatusTypeDef TIM_Delay(TIM_HandleTypeDef *htim, uint16_t delay)
|
||||
{
|
||||
if(check_null_ptr_2(htim, htim->Instance))
|
||||
return HAL_ERROR;
|
||||
|
||||
if(delay >= htim->Instance->ARR)
|
||||
{
|
||||
return HAL_ERROR;
|
||||
}
|
||||
htim->Instance->CNT = 0;
|
||||
while(1)
|
||||
{
|
||||
if(htim->Instance->CNT > delay)
|
||||
{
|
||||
return HAL_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Начать отсчет неблокирующей задержки.
|
||||
* @param htim Указатель на хендл таймера.
|
||||
* @return HAL status.
|
||||
* @details Сбрасывает счетчик для начала отсчета неблокирующей задержки.
|
||||
* @ref TIM_Delay_NonBlocking для проверки статуса задержки
|
||||
*/
|
||||
HAL_StatusTypeDef TIM_Delay_Start(TIM_HandleTypeDef *htim)
|
||||
{
|
||||
if(check_null_ptr_2(htim, htim->Instance))
|
||||
return HAL_ERROR;
|
||||
|
||||
htim->Instance->CNT = 0;
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Задержка в тиках таймера (неблокирующая).
|
||||
* @param htim Указатель на хендл таймера.
|
||||
* @param delay Задержка в тиках таймера.
|
||||
* @return HAL status.
|
||||
* @details Формирует задержку с блокировкой программы.
|
||||
* Перед ожиданием задержки надо запутстить таймер @ref TIM_Delay_Start
|
||||
* @note Таймер не должен использоваться на время этой задержки
|
||||
*/
|
||||
HAL_StatusTypeDef TIM_Delay_NonBlocking(TIM_HandleTypeDef *htim, uint16_t delay)
|
||||
{
|
||||
if(check_null_ptr_2(htim, htim->Instance))
|
||||
return HAL_ERROR;
|
||||
|
||||
if(delay >= htim->Instance->ARR)
|
||||
{
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
if(htim->Instance->CNT <= delay)
|
||||
{
|
||||
return HAL_BUSY;
|
||||
}
|
||||
else
|
||||
{
|
||||
return HAL_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Инициализация CLK и NVIC таймеров.
|
||||
* @param htim Указатель на хендл таймера.
|
||||
* @note Чтобы не генерировать функцию с иницилизацией неиспользуемых таймеров,
|
||||
дефайнами @ref TIM_INIT в @ref general_tim.h определяются используемые таймеры.
|
||||
*/
|
||||
void TIM_Base_MspInit(TIM_HandleTypeDef* htim, TIM_ITModeTypeDef it_mode)
|
||||
{
|
||||
if(check_null_ptr_2(htim, htim->Instance))
|
||||
return;
|
||||
|
||||
it_mode = it_mode&TIM_IT_CONF;
|
||||
#ifdef USE_TIM1
|
||||
if(htim->Instance==TIM1)
|
||||
{
|
||||
/* TIM2 clock enable */
|
||||
__HAL_RCC_TIM1_CLK_ENABLE();
|
||||
|
||||
/* TIM2 interrupt Init */
|
||||
if(it_mode)
|
||||
{
|
||||
HAL_NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TIM2
|
||||
if(htim->Instance==TIM2)
|
||||
{
|
||||
/* TIM2 clock enable */
|
||||
__HAL_RCC_TIM2_CLK_ENABLE();
|
||||
|
||||
/* TIM2 interrupt Init */
|
||||
if(it_mode)
|
||||
{
|
||||
HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(TIM2_IRQn);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TIM3
|
||||
if(htim->Instance==TIM3)
|
||||
{
|
||||
/* TIM3 clock enable */
|
||||
__HAL_RCC_TIM3_CLK_ENABLE();
|
||||
|
||||
/* TIM3 interrupt Init */
|
||||
if(it_mode)
|
||||
{
|
||||
HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(TIM3_IRQn);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TIM4
|
||||
if(htim->Instance==TIM4)
|
||||
{
|
||||
/* TIM4 clock enable */
|
||||
__HAL_RCC_TIM4_CLK_ENABLE();
|
||||
|
||||
/* TIM4 interrupt Init */
|
||||
if(it_mode)
|
||||
{
|
||||
HAL_NVIC_SetPriority(TIM4_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(TIM4_IRQn);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TIM5
|
||||
if(htim->Instance==TIM5)
|
||||
{
|
||||
/* TIM5 clock enable */
|
||||
__HAL_RCC_TIM5_CLK_ENABLE();
|
||||
|
||||
/* TIM5 interrupt Init */
|
||||
if(it_mode)
|
||||
{
|
||||
HAL_NVIC_SetPriority(TIM5_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(TIM5_IRQn);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TIM6
|
||||
if(htim->Instance==TIM6)
|
||||
{
|
||||
/* TIM6 clock enable */
|
||||
__HAL_RCC_TIM6_CLK_ENABLE();
|
||||
|
||||
/* TIM6 interrupt Init */
|
||||
if(it_mode)
|
||||
{
|
||||
HAL_NVIC_SetPriority(TIM6_DAC_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TIM7
|
||||
if(htim->Instance==TIM7)
|
||||
{
|
||||
/* TIM7 clock enable */
|
||||
__HAL_RCC_TIM7_CLK_ENABLE();
|
||||
|
||||
/* TIM7 interrupt Init */
|
||||
if(it_mode)
|
||||
{
|
||||
HAL_NVIC_SetPriority(TIM7_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(TIM7_IRQn);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TIM8
|
||||
if(htim->Instance==TIM8)
|
||||
{
|
||||
/* TIM8 clock enable */
|
||||
__HAL_RCC_TIM8_CLK_ENABLE();
|
||||
|
||||
/* TIM8 interrupt Init */
|
||||
if(it_mode)
|
||||
{
|
||||
HAL_NVIC_SetPriority(TIM8_UP_TIM13_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(TIM8_UP_TIM13_IRQn);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TIM9
|
||||
if(htim->Instance==TIM9)
|
||||
{
|
||||
/* TIM9 clock enable */
|
||||
__HAL_RCC_TIM9_CLK_ENABLE();
|
||||
|
||||
/* TIM9 interrupt Init */
|
||||
if(it_mode)
|
||||
{
|
||||
HAL_NVIC_SetPriority(TIM1_BRK_TIM9_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(TIM1_BRK_TIM9_IRQn);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TIM10
|
||||
if(htim->Instance==TIM10)
|
||||
{
|
||||
/* TIM10 clock enable */
|
||||
__HAL_RCC_TIM10_CLK_ENABLE();
|
||||
|
||||
/* TIM10 interrupt Init */
|
||||
if(it_mode)
|
||||
{
|
||||
HAL_NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TIM11
|
||||
if(htim->Instance==TIM11)
|
||||
{
|
||||
/* TIM11 clock enable */
|
||||
__HAL_RCC_TIM11_CLK_ENABLE();
|
||||
|
||||
/* TIM11 interrupt Init */
|
||||
if(it_mode)
|
||||
{
|
||||
HAL_NVIC_SetPriority(TIM1_TRG_COM_TIM11_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(TIM1_TRG_COM_TIM11_IRQn);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TIM12
|
||||
if(htim->Instance==TIM12)
|
||||
{
|
||||
/* TIM12 clock enable */
|
||||
__HAL_RCC_TIM12_CLK_ENABLE();
|
||||
|
||||
/* TIM12 interrupt Init */
|
||||
if(it_mode)
|
||||
{
|
||||
HAL_NVIC_SetPriority(TIM8_BRK_TIM12_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(TIM8_BRK_TIM12_IRQn);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TIM13
|
||||
if(htim->Instance==TIM13)
|
||||
{
|
||||
/* TIM13 clock enable */
|
||||
__HAL_RCC_TIM13_CLK_ENABLE();
|
||||
|
||||
/* TIM13 interrupt Init */
|
||||
if(it_mode)
|
||||
{
|
||||
HAL_NVIC_SetPriority(TIM8_UP_TIM13_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(TIM8_UP_TIM13_IRQn);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TIM14
|
||||
if(htim->Instance==TIM14)
|
||||
{
|
||||
/* TIM14 clock enable */
|
||||
__HAL_RCC_TIM14_CLK_ENABLE();
|
||||
|
||||
/* TIM14 interrupt Init */
|
||||
if(it_mode)
|
||||
{
|
||||
HAL_NVIC_SetPriority(TIM8_TRG_COM_TIM14_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(TIM8_TRG_COM_TIM14_IRQn);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/**
|
||||
* @brief Деинициализация CLK и NVIC таймеров.
|
||||
* @param htim Указатель на хендл таймера.
|
||||
* @note Чтобы не генерировать функцию с деиницилизацией неиспользуемых таймеров,
|
||||
дефайнами @ref TIM_INIT в @ref general_tim.h определяются используемые таймеры.
|
||||
*/
|
||||
void TIM_Base_MspDeInit(TIM_HandleTypeDef* htim)
|
||||
{
|
||||
if(check_null_ptr_2(htim, htim->Instance))
|
||||
return;
|
||||
|
||||
#ifdef USE_TIM1
|
||||
if(htim->Instance==TIM1)
|
||||
{
|
||||
__HAL_RCC_TIM1_FORCE_RESET();
|
||||
__HAL_RCC_TIM1_RELEASE_RESET();
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TIM2
|
||||
if(htim->Instance==TIM2)
|
||||
{
|
||||
__HAL_RCC_TIM2_FORCE_RESET();
|
||||
__HAL_RCC_TIM2_RELEASE_RESET();
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TIM3
|
||||
if(htim->Instance==TIM3)
|
||||
{
|
||||
__HAL_RCC_TIM3_FORCE_RESET();
|
||||
__HAL_RCC_TIM3_RELEASE_RESET();
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TIM4
|
||||
if(htim->Instance==TIM4)
|
||||
{
|
||||
__HAL_RCC_TIM4_FORCE_RESET();
|
||||
__HAL_RCC_TIM4_RELEASE_RESET();
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TIM5
|
||||
if(htim->Instance==TIM5)
|
||||
{
|
||||
__HAL_RCC_TIM5_FORCE_RESET();
|
||||
__HAL_RCC_TIM5_RELEASE_RESET();
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TIM6
|
||||
if(htim->Instance==TIM6)
|
||||
{
|
||||
__HAL_RCC_TIM6_FORCE_RESET();
|
||||
__HAL_RCC_TIM6_RELEASE_RESET();
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TIM7
|
||||
if(htim->Instance==TIM7)
|
||||
{
|
||||
__HAL_RCC_TIM7_FORCE_RESET();
|
||||
__HAL_RCC_TIM7_RELEASE_RESET();
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TIM8
|
||||
if(htim->Instance==TIM8)
|
||||
{
|
||||
__HAL_RCC_TIM8_FORCE_RESET();
|
||||
__HAL_RCC_TIM8_RELEASE_RESET();
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TIM9
|
||||
if(htim->Instance==TIM9)
|
||||
{
|
||||
__HAL_RCC_TIM9_FORCE_RESET();
|
||||
__HAL_RCC_TIM9_RELEASE_RESET();
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TIM10
|
||||
if(htim->Instance==TIM10)
|
||||
{
|
||||
__HAL_RCC_TIM10_FORCE_RESET();
|
||||
__HAL_RCC_TIM10_RELEASE_RESET();
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TIM11
|
||||
if(htim->Instance==TIM11)
|
||||
{
|
||||
__HAL_RCC_TIM11_FORCE_RESET();
|
||||
__HAL_RCC_TIM11_RELEASE_RESET();
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TIM12
|
||||
if(htim->Instance==TIM12)
|
||||
{
|
||||
__HAL_RCC_TIM12_FORCE_RESET();
|
||||
__HAL_RCC_TIM12_RELEASE_RESET();
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TIM13
|
||||
if(htim->Instance==TIM13)
|
||||
{
|
||||
__HAL_RCC_TIM13_FORCE_RESET();
|
||||
__HAL_RCC_TIM13_RELEASE_RESET();
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TIM14
|
||||
if(htim->Instance==TIM14)
|
||||
{
|
||||
__HAL_RCC_TIM14_FORCE_RESET();
|
||||
__HAL_RCC_TIM14_RELEASE_RESET();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
//-------------------------TIM INIT FUNCTIONS------------------------
|
||||
//-------------------------------------------------------------------
|
||||
@@ -1,383 +0,0 @@
|
||||
/**
|
||||
**************************************************************************
|
||||
* @file general_uart.c
|
||||
* @brief Модуль для инициализации UART.
|
||||
**************************************************************************
|
||||
Реализация функций для работы с UART:
|
||||
- Инициализация UART и его линий RX/TX
|
||||
- Настройка DMA для UART
|
||||
- Настройка GPIO для UART
|
||||
- Настройка NVIC и тактирования UART
|
||||
**************************************************************************/
|
||||
#include "general_uart.h"
|
||||
#include "general_gpio.h"
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
//------------------------UART INIT FUNCTIONS------------------------
|
||||
/**
|
||||
* @brief Инициализация UART с помощью структуры UART_SettingsTypeDef.
|
||||
* @param suart Указатель на структуру с настройками UART.
|
||||
* @return HAL status.
|
||||
* @details
|
||||
* Инициализирует UART и его GPIO и при необходимости DMA.
|
||||
* Настройка аналогична HAL_UART_Init
|
||||
* @code
|
||||
* suart.huart.Init...
|
||||
* @endcode
|
||||
* но дополнительно надо прописать пины RX/TX @ref UART_SettingsTypeDef
|
||||
* @code
|
||||
* suart->GPIOx, suart->GPIO_PIN_RX, suart->GPIO_PIN_TX
|
||||
* @endcode
|
||||
*/
|
||||
HAL_StatusTypeDef UART_Base_Init(UART_SettingsTypeDef *suart)
|
||||
{ // function takes setting structure for init
|
||||
|
||||
// check is settings are valid
|
||||
if(UART_Check_Init_Struct(suart) != HAL_OK)
|
||||
return HAL_ERROR;
|
||||
|
||||
suart->huart.Init.Mode = UART_MODE_TX_RX;
|
||||
|
||||
UART_MspInit(&suart->huart);
|
||||
|
||||
|
||||
if (HAL_UART_Init(&suart->huart) != HAL_OK)
|
||||
{
|
||||
MyLibs_Error_Handler();
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
// init gpio from UARTSettings structure
|
||||
UART_GPIO_Init(suart->GPIOx, suart->GPIO_PIN_RX, suart->GPIO_PIN_TX);
|
||||
|
||||
__HAL_UART_ENABLE_IT(&suart->huart, UART_IT_IDLE);
|
||||
// init dma from UARTSettings structure if need
|
||||
if (suart->DMAChannel != 0)
|
||||
UART_DMA_Init(&suart->huart, suart->huart.hdmarx, suart->DMAChannel, suart->DMA_CHANNEL_X);
|
||||
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Инициализация GPIO для UART.
|
||||
* @param GPIOx Порт для настройки.
|
||||
* @param GPIO_PIN_RX Пин для приема.
|
||||
* @param GPIO_PIN_TX Пин для передачи.
|
||||
*/
|
||||
void UART_GPIO_Init(GPIO_TypeDef *GPIOx, uint16_t GPIO_PIN_RX, uint16_t GPIO_PIN_TX)
|
||||
{ // function takes port and pins (for rx and tx)
|
||||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
|
||||
// choose port for enable clock
|
||||
GPIO_Clock_Enable(GPIOx);
|
||||
|
||||
//USART3 GPIO Configuration
|
||||
//GPIO_PIN_TX ------> USART_TX
|
||||
//GPIO_PIN_RX ------> USART_RX
|
||||
|
||||
#if defined(STM32F4xx) // gpio init for 407
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_TX|GPIO_PIN_RX;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
||||
GPIO_InitStruct.Alternate = GPIO_AF7_USART3;
|
||||
HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);
|
||||
#elif defined(STM32F1xx) // gpio init for atm403/stm103
|
||||
//GPIO_PIN_TX ------> USART_TX
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_TX;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
|
||||
HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);
|
||||
|
||||
// GPIO_PIN_RX ------> USART_RX
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_RX;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Инициализация DMA для UART.
|
||||
* @param huart Указатель на хендл UART.
|
||||
* @param hdma_rx Указатель на хендл DMA для линии приема UART.
|
||||
* @param DMAChannel Указатель на канал DMA/поток DMA в STM32F407.
|
||||
* @param DMA_CHANNEL_X Канал DMA.
|
||||
*/
|
||||
void UART_DMA_Init(UART_HandleTypeDef *huart, DMA_HandleTypeDef *hdma_rx, DMA_Stream_TypeDef *DMAChannel, uint32_t DMA_CHANNEL_X)
|
||||
{ // function takes uart and dma handlers and dmachannel for uart
|
||||
// for now only dma rx is supported, tx maybe later if needed
|
||||
// calc defines on boot_project_setup.h
|
||||
|
||||
/* USART3 DMA Init */
|
||||
/* USART3_RX Init */
|
||||
|
||||
hdma_rx->Instance = DMAChannel;
|
||||
#if defined(STM32F4xx) // dma channel choose for 407
|
||||
hdma_rx->Init.Channel = DMA_CHANNEL_X;
|
||||
#endif
|
||||
hdma_rx->Init.Direction = DMA_PERIPH_TO_MEMORY;
|
||||
hdma_rx->Init.PeriphInc = DMA_PINC_DISABLE;
|
||||
hdma_rx->Init.MemInc = DMA_MINC_ENABLE;
|
||||
hdma_rx->Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
|
||||
hdma_rx->Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
|
||||
hdma_rx->Init.Mode = DMA_CIRCULAR;
|
||||
hdma_rx->Init.Priority = DMA_PRIORITY_LOW;
|
||||
if (HAL_DMA_Init(hdma_rx) != HAL_OK)
|
||||
{
|
||||
MyLibs_Error_Handler();
|
||||
}
|
||||
|
||||
__USER_LINKDMA(huart,hdmarx,hdma_rx);
|
||||
|
||||
|
||||
// __USER_LINKDMA is need because __HAL_LINKDMA is written for global defined hdma_rx
|
||||
// so you get error because hal uses . insted of ->
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Настройка тактирования и прерываний UART.
|
||||
* @param huart Указатель на хендл UART.
|
||||
* @note Чтобы не генерировать функцию с иницилизацией неиспользуемых UART,
|
||||
дефайнами @ref UART_INIT в @ref general_uart.h определяются используемые UART.
|
||||
*/
|
||||
void UART_MspInit(UART_HandleTypeDef *huart) // analog for hal function
|
||||
{
|
||||
// __RCC_DMA_UART_CLK_ENABLE();
|
||||
// /* DMA interrupt init */
|
||||
// /* DMA1_Stream1_IRQn interrupt configuration */
|
||||
// HAL_NVIC_SetPriority(DMA_UART_IRQn, 0, 0);
|
||||
// HAL_NVIC_EnableIRQ(DMA_UART_IRQn);
|
||||
|
||||
// rcc, dma and interrupt init for USARTs
|
||||
// GPIO init was moved to own functions UART_GPIO_Init
|
||||
if(0);
|
||||
#ifdef USE_USART1
|
||||
else if(huart->Instance==USART1)
|
||||
{
|
||||
|
||||
/* DMA2 clock enable */
|
||||
__HAL_RCC_DMA2_CLK_ENABLE();
|
||||
/* DMA interrupt init */
|
||||
HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
|
||||
|
||||
/* USART1 clock enable */
|
||||
__HAL_RCC_USART1_CLK_ENABLE();
|
||||
|
||||
/* USART1 interrupt Init */
|
||||
HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(USART1_IRQn);
|
||||
}
|
||||
#endif // USE_USART1
|
||||
#ifdef USE_USART2
|
||||
else if(huart->Instance==USART2)
|
||||
{
|
||||
/* DMA1 clock enable */
|
||||
__HAL_RCC_DMA1_CLK_ENABLE();
|
||||
/* DMA interrupt init */
|
||||
HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);
|
||||
|
||||
/* USART2 clock enable */
|
||||
__HAL_RCC_USART2_CLK_ENABLE();
|
||||
|
||||
/* USART2 interrupt Init */
|
||||
HAL_NVIC_SetPriority(USART2_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(USART2_IRQn);
|
||||
}
|
||||
#endif // USE_USART2
|
||||
#ifdef USE_USART3
|
||||
else if(huart->Instance==USART3)
|
||||
{
|
||||
/* DMA1 clock enable */
|
||||
__HAL_RCC_DMA1_CLK_ENABLE();
|
||||
/* DMA interrupt init */
|
||||
HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
|
||||
|
||||
/* USART3 clock enable */
|
||||
__HAL_RCC_USART3_CLK_ENABLE();
|
||||
/* USART3 interrupt Init */
|
||||
HAL_NVIC_SetPriority(USART3_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(USART3_IRQn);
|
||||
}
|
||||
#endif // USE_USART3
|
||||
#ifdef USE_UART4
|
||||
else if(huart->Instance==UART4)
|
||||
{
|
||||
/* DMA1 clock enable */
|
||||
__HAL_RCC_DMA1_CLK_ENABLE();
|
||||
/* DMA interrupt init */
|
||||
HAL_NVIC_SetPriority(DMA1_Stream2_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(DMA1_Stream2_IRQn);
|
||||
|
||||
/* UART4 clock enable */
|
||||
__HAL_RCC_UART4_CLK_ENABLE();
|
||||
|
||||
/* UART4 interrupt Init */
|
||||
HAL_NVIC_SetPriority(UART4_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(UART4_IRQn);
|
||||
}
|
||||
#endif // USE_UART4
|
||||
#ifdef USE_UART5
|
||||
else if(huart->Instance==UART5)
|
||||
{
|
||||
/* DMA1 clock enable */
|
||||
__HAL_RCC_DMA1_CLK_ENABLE();
|
||||
/* DMA interrupt init */
|
||||
HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
|
||||
|
||||
/* UART5 clock enable */
|
||||
__HAL_RCC_DMA1_CLK_ENABLE();
|
||||
|
||||
/* UART5 interrupt Init */
|
||||
HAL_NVIC_SetPriority(UART5_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(UART5_IRQn);
|
||||
}
|
||||
#endif // USE_UART5
|
||||
#ifdef USE_USART6
|
||||
else if(huart->Instance==USART6)
|
||||
{
|
||||
/* DMA2 clock enable */
|
||||
__HAL_RCC_DMA2_CLK_ENABLE();
|
||||
/* DMA interrupt init */
|
||||
HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);
|
||||
|
||||
/* USART6 clock enable */
|
||||
__HAL_RCC_USART6_CLK_ENABLE();
|
||||
|
||||
/* USART6 interrupt Init */
|
||||
HAL_NVIC_SetPriority(USART6_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(USART6_IRQn);
|
||||
}
|
||||
#endif // USE_USART6
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Деинициализация тактирования и прерываний UART.
|
||||
* @param huart Указатель на хендл UART.
|
||||
* @note Чтобы не генерировать функцию с деиницилизацией неиспользуемых UART,
|
||||
дефайнами @ref UART_INIT в @ref general_uart.h определяются используемые UART.
|
||||
*/
|
||||
void UART_MspDeInit(UART_HandleTypeDef *huart) // analog for hal function
|
||||
{
|
||||
// rcc, dma and interrupt init for USARTs
|
||||
// GPIO init was moved to own functions UART_GPIO_Init
|
||||
if(0);
|
||||
#ifdef USE_USART1
|
||||
else if(huart->Instance==USART1)
|
||||
{
|
||||
|
||||
// /* DMA2 clock enable */
|
||||
// __HAL_RCC_DMA2_CLK_ENABLE();
|
||||
// /* DMA interrupt init */
|
||||
// HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 0, 0);
|
||||
// HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
|
||||
|
||||
/* USART1 clock reset */
|
||||
__HAL_RCC_USART1_FORCE_RESET();
|
||||
__HAL_RCC_USART1_RELEASE_RESET();
|
||||
}
|
||||
#endif // USE_USART1
|
||||
#ifdef USE_USART2
|
||||
else if(huart->Instance==USART2)
|
||||
{
|
||||
// /* DMA1 clock enable */
|
||||
// __HAL_RCC_DMA1_CLK_ENABLE();
|
||||
// /* DMA interrupt init */
|
||||
// HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 0, 0);
|
||||
// HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);
|
||||
|
||||
/* USART2 clock reset */
|
||||
__HAL_RCC_USART2_FORCE_RESET();
|
||||
__HAL_RCC_USART2_RELEASE_RESET();
|
||||
}
|
||||
#endif // USE_USART2
|
||||
#ifdef USE_USART3
|
||||
else if(huart->Instance==USART3)
|
||||
{
|
||||
// /* DMA1 clock enable */
|
||||
// __HAL_RCC_DMA1_CLK_ENABLE();
|
||||
// /* DMA interrupt init */
|
||||
// HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0);
|
||||
// HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
|
||||
|
||||
/* USART3 clock reset */
|
||||
__HAL_RCC_USART3_FORCE_RESET();
|
||||
__HAL_RCC_USART3_RELEASE_RESET();
|
||||
}
|
||||
#endif // USE_USART3
|
||||
#ifdef USE_UART4
|
||||
else if(huart->Instance==UART4)
|
||||
{
|
||||
// /* DMA1 clock enable */
|
||||
// __HAL_RCC_DMA1_CLK_ENABLE();
|
||||
// /* DMA interrupt init */
|
||||
// HAL_NVIC_SetPriority(DMA1_Stream2_IRQn, 0, 0);
|
||||
// HAL_NVIC_EnableIRQ(DMA1_Stream2_IRQn);
|
||||
|
||||
/* UART4 clock reset */
|
||||
__HAL_RCC_UART4_FORCE_RESET();
|
||||
__HAL_RCC_UART4_RELEASE_RESET();
|
||||
}
|
||||
#endif // USE_UART4
|
||||
#ifdef USE_UART5
|
||||
else if(huart->Instance==UART5)
|
||||
{
|
||||
// /* DMA1 clock enable */
|
||||
// __HAL_RCC_DMA1_CLK_ENABLE();
|
||||
// /* DMA interrupt init */
|
||||
// HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 0, 0);
|
||||
// HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
|
||||
|
||||
/* UART5 clock reset */
|
||||
__HAL_RCC_UART5_FORCE_RESET();
|
||||
__HAL_RCC_UART5_RELEASE_RESET();
|
||||
}
|
||||
#endif // USE_UART5
|
||||
#ifdef USE_USART6
|
||||
else if(huart->Instance==USART6)
|
||||
{
|
||||
// /* DMA2 clock enable */
|
||||
// __HAL_RCC_DMA2_CLK_ENABLE();
|
||||
// /* DMA interrupt init */
|
||||
// HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 0, 0);
|
||||
// HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);
|
||||
|
||||
/* USART6 clock reset */
|
||||
__HAL_RCC_USART6_FORCE_RESET();
|
||||
__HAL_RCC_USART6_RELEASE_RESET();
|
||||
}
|
||||
#endif // USE_USART6
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Проверка корректности структуры инициализации UART.
|
||||
* @param suart Указатель на структуру с настройками UART.
|
||||
* @return HAL status.
|
||||
*/
|
||||
HAL_StatusTypeDef UART_Check_Init_Struct(UART_SettingsTypeDef *suart)
|
||||
{
|
||||
// check is settings are valid
|
||||
if (!IS_UART_INSTANCE(suart->huart.Instance))
|
||||
return HAL_ERROR;
|
||||
|
||||
if (!IS_UART_BAUDRATE(suart->huart.Init.BaudRate) || (suart->huart.Init.BaudRate == NULL))
|
||||
return HAL_ERROR;
|
||||
|
||||
if (!IS_GPIO_ALL_INSTANCE(suart->GPIOx))
|
||||
return HAL_ERROR;
|
||||
|
||||
if (!IS_GPIO_PIN(suart->GPIO_PIN_RX) && !IS_GPIO_PIN(suart->GPIO_PIN_TX)) // if both pins arent set up
|
||||
return HAL_ERROR;
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
//------------------------UART INIT FUNCTIONS------------------------
|
||||
//-------------------------------------------------------------------
|
||||
@@ -22,8 +22,8 @@
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define TRACKERS_ENABLE ///< Включить трекеры
|
||||
#define SERIAL_TRACE_ENABLE ///< Включить serial трассировку
|
||||
//#define TRACKERS_ENABLE ///< Включить трекеры
|
||||
//#define SERIAL_TRACE_ENABLE ///< Включить serial трассировку
|
||||
#define RTT_TRACE_ENABLE ///< Включить serial трассировку через RTT
|
||||
#define SWO_TRACE_ENABLE ///< Включить serial трассировку через SWO
|
||||
/**
|
||||
@@ -54,22 +54,58 @@
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup EVOLVE_CONFIG Evolve configs
|
||||
* @addtogroup FILTER_CONFIG Filter configs
|
||||
* @ingroup MYLIBS_CONFIG
|
||||
* @brief Конфигурация однослойного персептрона и алгоритма обучения
|
||||
* @brief Конфигурация фильтров
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define ENABLE_EVOLVE_OPTIMIZATION ///< Включить оптимизацию параметров
|
||||
#define EVOLVE_MAX_PARAMS 20 ///< Максимальное количество параметров
|
||||
#define EVOLVE_MAX_CANDIDATES 100 ///< Максимальное количество кандидатов для обучения
|
||||
|
||||
/** EVOLVE_CONFIG
|
||||
//#define FILTERS_ENABLE ///< Включить библиотеку фильтров
|
||||
//#define FILTER_MEDIAN_MAX_SIZE ///< Максимальный размер окна медианного фильтра (по умолчанию 5)
|
||||
//#define FILTER_AVERAGE_MAX_SIZE ///< Максимальный размер окна усредняющего фильтра (по умолчанию 8)
|
||||
//#define FILTER_POLY_MAX_ORDER ///< Максимальный порядок полинома (по умолчанию 4)
|
||||
#define FILTERS_DISABLE_MOVING_AVERAGE
|
||||
/** GEN_CONFIG
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup GEN_CONFIG Genetic configs
|
||||
* @ingroup MYLIBS_CONFIG
|
||||
* @brief Конфигурация генетического алгоритма обучения
|
||||
* @{
|
||||
*/
|
||||
|
||||
//#define GEN_OPTIMIZATION_ENABLE ///< Включить оптимизацию параметров
|
||||
#define GEN_MAX_PARAMS 20 ///< Максимальное количество параметров
|
||||
#define GEN_MAX_CANDIDATES 100 ///< Максимальное количество кандидатов для обучения
|
||||
|
||||
/** GEN_CONFIG
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup GEN_CONFIG Genetic configs
|
||||
* @ingroup MYLIBS_CONFIG
|
||||
* @brief Конфигурация генетического алгоритма обучения
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
//#define BENCH_TIME_ENABLE ///< Включить бенч времени
|
||||
#define BENCH_TIME_MAX_CHANNELS 16 ///< Максимальное количество каналов измерения
|
||||
|
||||
/** GEN_CONFIG
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup LIBS_CONFIG Libraries configs
|
||||
* @ingroup MYLIBS_CONFIG
|
||||
@@ -79,12 +115,12 @@
|
||||
|
||||
#define local_time() uwTick ///< Локальное время
|
||||
|
||||
#define INCLUDE_EVOLVE_OPTIMIZER ///< Подключить библиотеку для оптимизации параметров
|
||||
#define INCLUDE_GEN_OPTIMIZER ///< Подключить библиотеку для оптимизации параметров
|
||||
#define INCLUDE_BIT_ACCESS_LIB ///< Подключить библиотеку с typedef с битовыми полями
|
||||
#define INCLUDE_TRACKERS_LIB ///< Подключить библиотеку с трекерами
|
||||
#define INCLUDE_TRACE_LIB ///< Подключить библиотеку с трейсами
|
||||
#define INCLUDE_GENERAL_PERIPH_LIBS ///< Подключить библиотеку с периферией
|
||||
#define FREERTOS_DELAY ///< Использовать FreeRTOS задержку, вместо HAL
|
||||
//#define FREERTOS_DELAY ///< Использовать FreeRTOS задержку, вместо HAL
|
||||
|
||||
/** LIBS_CONFIG
|
||||
* @}
|
||||
@@ -93,4 +129,4 @@
|
||||
/** MYLIBS_CONFIG
|
||||
* @}
|
||||
*/
|
||||
#endif //__MYLIBS_CONFIG_H_
|
||||
#endif //__MYLIBS_CONFIG_H_
|
||||
92
__mylibs_include.h
Normal file
92
__mylibs_include.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
**************************************************************************
|
||||
* @file mylibs_include.h
|
||||
* @brief Заголочный файл для всех библиотек
|
||||
**************************************************************************
|
||||
* @details
|
||||
Здесь нужно собрать библиотеки и дефайны, которые должны быть видны во всем проекте,
|
||||
чтобы не подключать 100 инклюдов в каждом ".c" файле
|
||||
**************************************************************************
|
||||
* @defgroup MYLIBS_ALL My Libs
|
||||
* @brief Все используемые MyLibs библиотеки
|
||||
* @details
|
||||
Для подключения библиотеки необходимо:
|
||||
- Сконфигурировать mylibs_config.h:
|
||||
- Подключить заголовочный файл HAL библиотеки конкретного МК (напр. stm32f4xx_hal.h)
|
||||
- Подключить другие заголовочные файлы которые общие для всего проекта и должны быть видны
|
||||
- Подключить mylibs_include.h туда, где необходим доступ к библиотекам.
|
||||
|
||||
*************************************************************************/
|
||||
#ifndef __MYLIBS_INCLUDE_H_
|
||||
#define __MYLIBS_INCLUDE_H_
|
||||
|
||||
#include "mylibs_defs.h"
|
||||
|
||||
|
||||
#ifdef ARM_MATH_CM4
|
||||
#include "arm_math.h"
|
||||
#else
|
||||
#include "math.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef INCLUDE_BIT_ACCESS_LIB
|
||||
#include "bit_access.h"
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_TRACKERS_LIB
|
||||
#include "trackers.h"
|
||||
#else
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_TRACE_LIB
|
||||
#include "trace.h"
|
||||
#else
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_GEN_OPTIMIZER
|
||||
#include "gen_optimizer.h"
|
||||
#else
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef INCLUDE_BENCH_TEST
|
||||
#include "bench_time.h"
|
||||
#else //BENCH_TIME_ENABLE
|
||||
#endif //BENCH_TIME_ENABLE
|
||||
|
||||
|
||||
#ifdef INCLUDE_FILTERS
|
||||
#include "filters.h"
|
||||
#else //INCLUDE_FILTERS
|
||||
#endif //INCLUDE_FILTERS
|
||||
|
||||
|
||||
#ifdef INCLUDE_GENERAL_PERIPH_LIBS
|
||||
|
||||
#include "__general_flash.h"
|
||||
#include "general_gpio.h"
|
||||
#ifdef HAL_SPI_MODULE_ENABLED
|
||||
#include "general_spi.h"
|
||||
#endif
|
||||
#ifdef HAL_UART_MODULE_ENABLED
|
||||
#include "general_uart.h"
|
||||
#endif
|
||||
#ifdef HAL_TIM_MODULE_ENABLED
|
||||
#include "general_tim.h"
|
||||
#endif
|
||||
|
||||
#endif //INCLUDE_GENERAL_PERIPH_LIBS
|
||||
|
||||
|
||||
|
||||
|
||||
/////////////////////////---USER SETTINGS---/////////////////////////
|
||||
// user includes
|
||||
|
||||
// user settings
|
||||
/////////////////////////---USER SETTINGS---/////////////////////////
|
||||
|
||||
|
||||
#endif // __MYLIBS_INCLUDE_H_
|
||||
98
mainpage.h
98
mainpage.h
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Скачать HTML документацию можно здесь:
|
||||
* https://git.arktika.cyou/Razvalyaev/STM32_ExtendedLibs/archive/v0.02.zip
|
||||
*/
|
||||
/**
|
||||
@mainpage
|
||||
|
||||
|
||||
@section overview Обзор
|
||||
MyLibs - это набор библиотек для удобной работы с STM32.
|
||||
|
||||
\htmlonly
|
||||
<a href="https://git.arktika.cyou/Razvalyaev/STM32_ExtendedLibs/src/branch/release">Актуальная версия</a>
|
||||
\endhtmlonly
|
||||
|
||||
@subsection features Основные возможности
|
||||
|
||||
@subsubsection utils_module Общие утилиты (@ref MYLIBS_DEFINES)
|
||||
- Макросы для задержек и утилит (@ref DELAYS_DEFINES и @ref UTILS_DEFINES)
|
||||
- Трекеры для статистики и отладки (@ref TRACKERS и @ref TRACE)
|
||||
- Эволюционный алгоритм для оптимизации параметров (@ref EVOLVE_OPTIMIZER)
|
||||
- Битовый доступ к регистрам через union (@ref BIT_ACCESS_DEFINES)
|
||||
|
||||
@subsubsection trace_module Трассировка @ref TRACE
|
||||
- Serial трассировка через SWO и RTT (@ref TRACE_SERIAL)
|
||||
- GPIO трассировка для отладки (@ref TRACE_GPIO)
|
||||
- Сохранение логов в Flash память (@ref TRACE_RTT_FLASH)
|
||||
- Обработка HardFault с сохранением контекста (@ref TRACE_HARDFAULT)
|
||||
|
||||
@subsubsection gpio_module Модуль GPIO @ref MY_LIBS_GPIO
|
||||
- Инициализация портов и тактирования (@ref MYLIBS_GPIO_GENERAL)
|
||||
- Управление светодиодами (включение/выключение, моргание, плавное затухание) (@ref MYLIBS_GPIO_LEDS)
|
||||
- Работа с кнопками (чтение состояния, фильтрация дребезга) (@ref MYLIBS_GPIO_SWITCH)
|
||||
|
||||
@subsubsection tim_module Модуль таймеров @ref MY_LIBS_TIM
|
||||
- Базовая инициализация таймеров (@ref MYLIBS_TIM_GENERAL)
|
||||
- Формирование задержек (блокирующие и неблокирующие) (@ref MYLIBS_TIM_DELAY)
|
||||
- Работа с энкодерами (чтение положения, обработка кнопок) (@ref MYLIBS_TIM_ENCODER)
|
||||
- Настройка ШИМ и Output Compare (@ref MYLIBS_TIM_OC)
|
||||
|
||||
@subsubsection uart_module Модуль UART @ref MY_LIBS_UART
|
||||
- Базовая инициализация UART и его пинов одной функцией (@ref UART_Base_Init)
|
||||
|
||||
@subsubsection spi_module Модуль SPI @ref MY_LIBS_SPI
|
||||
- Базовая инициализация SPI и пинов одной функцией (@ref SPI_Base_Init)
|
||||
|
||||
@subsection structure Структура проекта
|
||||
|
||||
@code
|
||||
ProjectRoot/
|
||||
├── MyLibs/ # Общие библиотеки, независимые от платформы (или почти)
|
||||
│ ├── inc/
|
||||
│ │ ├── mylibs_include.h # Главный include файл
|
||||
│ │ ├── mylibs_config.h # Конфигурация библиотек
|
||||
│ │ ├── mylibs_defs.h # Общие определения и макросы
|
||||
│ │ ├── bit_access.h # Битовый доступ к регистрам
|
||||
│ │ ├── evolve_optimizer.h # Оптимизатор (генетический алгоритм)
|
||||
│ │ ├── trackers.h # Трекеры для отладки
|
||||
│ │ └── trace.h # Трассировка и логирование
|
||||
│ └── src/
|
||||
│
|
||||
├──RTT # Библиотека RTT
|
||||
│ ├── __SEGGER_RTT_Conf.h # Конфигурационный файл RTT
|
||||
│ ├── SEGGER_RTT.c # Основной модуль RTT
|
||||
│ ├── SEGGER_RTT.h # Основной заголовок RTT
|
||||
│ ├── SEGGER_RTT_ASM_ARMv7M.S # Ассемблерная оптимизация для ARMv7M
|
||||
│ └── SEGGER_RTT_printf.c # Реализация printf() через RTT
|
||||
│
|
||||
└── STM32_General # Работа с периферией STM32
|
||||
├── inc/
|
||||
│ ├── general_gpio.h # Работа с GPIO
|
||||
│ ├── general_spi.h # Работа с SPI
|
||||
│ ├── general_tim.h # Работа с таймерами
|
||||
│ └── general_uart.h # Работа с UART
|
||||
└── src/
|
||||
├── general_gpio.c # Реализация GPIO
|
||||
├── general_spi.c # Реализация SPI
|
||||
├── general_tim.c # Реализация TIM
|
||||
└── general_uart.c # Реализация UART
|
||||
@endcode
|
||||
|
||||
|
||||
|
||||
|
||||
@subsection usage_basic Использование
|
||||
|
||||
Инструкция по подключению:
|
||||
|
||||
1. Настройте конфигурацию @ref MYLIBS_CONFIG в @ref mylibs_config.h
|
||||
|
||||
2. Подключите главный заголовочный файл:
|
||||
@code
|
||||
#include "mylibs_include.h"
|
||||
@endcode
|
||||
|
||||
3. Используйте нужные модули в своем коде. Примеры использования приведены в соответствующей теме
|
||||
|
||||
*/
|
||||
Reference in New Issue
Block a user