Files
VK035_Template/Core/App/sysclk.c
Razvalyaev f3e76e105a Добавлено:
- рефакторинг названий:
	- маленькие буквы - инит периферии
	- ТакойСтильФункций - API для использования
- сделаны шапки с инструкциями к функциями
- доработан ацп секвенсора
- доработан систем тики. можно настроить его на разные частоты и подключить коллбеки на разный период
- в gpio добавлены функции для кнопок и диодов
- генерация бинарника
2025-12-27 23:20:03 +03:00

307 lines
11 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
******************************************************************************
* @file sysclk.c
* @author Разваляев Алексей
* @brief Драйвер тактирования системы на основе PLIB035.
* Этот файл содержит:
* + Инициализацию системного тактирования (PLL, осцилляторы)
* + Настройку частоты ядра и периферии
* + Управление системным таймером (SysTick)
* + Функции для работы со временем (millis, micros)
* + Систему периодических коллбеков
* + Настройку тактирования периферии
*
******************************************************************************
* @attention
*
* Использование этого драйвера предполагает наличие корректных настроек:
* - Определены константы SYSCLK_CORE_CLOCK_MHZ и SYSCLK_Oscil_Type в periph_config.h
* - Определен тип системного тика SYSCLK_TickType в periph_config.h
*
******************************************************************************
* @verbatim
==============================================================================
##### Как использовать этот драйвер #####
==============================================================================
1. Настройка периферии (periph_config.h):
(+) Определить SYSCLK_CORE_CLOCK_MHZ - частота ядра в МГц (например, 100)
(+) Определить SYSCLK_Oscil_Type - тип осциллятора (RCU_Oscil_OSE или RCU_Oscil_OSI)
(+) Определить SYSCLK_TickType - тип системного тика (SYSCLK_Tick_1us, SYSCLK_Tick_1ms и т.д.)
2. Инициализация тактирования:
(+) sysclk_init() — обязательный вызов в начале программы
- Автоматически настраивает PLL для заданной частоты
- Настраивает SysTick для генерации системных тиков
- Обновляет SystemCoreClock
3. Работа со временем:
(+) millis() — получение текущего времени в миллисекундах
(+) micros() — получение текущего времени в микросекундах
(+) sysclk_irq_handler() — обработчик прерываний SysTick (должен вызываться из SysTick_Handler)
4. Система коллбеков:
(+) SYSCLK_Set_Callback() — добавление периодического коллбека
- Коллбеки автоматически вызываются в sysclk_irq_handler() с заданным периодом
- Максимальное количество коллбеков: SYSCLK_NUMB_OF_CUSTOM_CALLBACKS
5. Настройка тактирования Периферии:
(+) АЦП: rcu_set_clock_adc(ClkSrc, ClkMHz, state)
- ClkSrc: источник тактирования (RCU_PeriphClk_OSEClk, RCU_PeriphClk_PLLClk и т.д.)
- ClkMHz: желаемая частота ADC в МГц
- state: включение/выключение тактирования
6. Особенности работы:
(+) Системные тики работают на основе SysTick
(+) Поддерживаются различные периоды тиков от 1 мкс до 100 мс
(+) Переполнение счетчиков происходит через ~49 дней
@endverbatim
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "periph_config.h"
/* Private variables ---------------------------------------------------------*/
/** @brief Счетчик миллисекунд */
__IO uint32_t msTick = 0;
/** @brief Счетчик микросекунд */
__IO uint32_t usTick = 0;
/** @brief Инкремент для миллисекунд */
static __IO uint32_t msTickInc = 0;
/** @brief Инкремент для микросекунд */
static __IO uint32_t usTickInc = 0;
/** @brief Обработчик системных коллбеков */
static SYSCLK_CallbackHandleTypeDef hsyscb = {0};
//-- Defines -------------------------------------------------------------------
//-- Private function prototypes -----------------------------------------------
static inline void millis_inc(void);
static inline void micros_inc(void);
//-- Peripheral init functions -------------------------------------------------
/**
* @brief Инициализация системного тактирования.
* @details Настраивает PLL, SysTick и счетчики времени.
* Должна быть вызвана первой в функции main().
*/
void sysclk_init(void)
{
OperationStatus status;
status = RCU_PLL_AutoConfig(SYSCLK_CORE_CLOCK_MHZ*__MHZ, SYSCLK_Oscil_Type);
if (status == ERROR)
{
Error_Handler();
}
SystemCoreClockUpdate();
// RCU_ClkOutConfig(RCU_SysPeriphClk_PLLClk, 1, ENABLE);
// RCU_ClkOutCmd(ENABLE);
SysTick_Config(SYSCLK_CORE_CLOCK_MHZ*__MHZ/SYSCLK_TickType);
switch(SYSCLK_TickType)
{
case SYSCLK_Tick_1us:
usTickInc = 1;
msTickInc = 1;
break;
case SYSCLK_Tick_10us:
usTickInc = 10;
msTickInc = 1;
break;
case SYSCLK_Tick_100us:
usTickInc = 100;
msTickInc = 1;
break;
case SYSCLK_Tick_1ms:
usTickInc = 1000;
msTickInc = 1;
break;
case SYSCLK_Tick_10ms:
usTickInc = 10000;
msTickInc = 10;
break;
case SYSCLK_Tick_100ms:
usTickInc = 100000;
msTickInc = 100;
break;
default:
/* Должен быть определен в periph_config.h */
Error_Handler();
break;
}
}
/**
* @brief Общий обработчик прерываний SysClock
* @details Обрабатывает мс и мкс и вызывает коллбеки
*/
void sysclk_irq_handler(void)
{
static uint32_t usAccumulator = 0; // Накопитель мкс
/* Инкремент микросекунд */
micros_inc();
if(msTickInc == 1)
{
/* Аккумулятивный метод для миллисекунд (без деления) */
usAccumulator += usTickInc;
if (usAccumulator >= 1000) {
millis_inc();
usAccumulator -= 1000; // Вычитание быстрее деления
}
}
else
{
millis_inc();
}
/* Вызов зарегистрированных коллбеков */
for(int i = 0; i < hsyscb.CallbackInUse; i++)
{
if(hsyscb.Callback[i] != NULL)
{
/* Проверка истекшего времени */
uint32_t elapsed = msTick - hsyscb.CallbackPrevMs[i];
if(elapsed >= hsyscb.CallbackPeriod[i])
{
/* Обновление времени последнего вызова и вызов коллбека */
hsyscb.CallbackPrevMs[i] = msTick;
hsyscb.Callback[i]();
}
}
}
}
/**
* @brief Добавление периодического коллбека.
* @param Callback Указатель на функцию-коллбек
* @param PeriodInMs Период вызова коллбека в миллисекундах
* @retval OperationStatus OK при успехе, ERROR при ошибке
* @note Максимальное количество коллбеков: SYSCLK_NUMB_OF_CUSTOM_CALLBACKS
* @note Минимальный период: текущий период тика SysTick
*/
OperationStatus SYSCLK_Set_Callback(void (*Callback)(void), uint32_t PeriodInMs)
{
/* Проверка валидности указателя на функцию */
if(Callback == NULL)
return ERROR;
/* Проверка минимального периода */
if(PeriodInMs < msTickInc)
return ERROR;
/* Проверка доступности свободных слотов */
if(hsyscb.CallbackInUse >= SYSCLK_NUMB_OF_CUSTOM_CALLBACKS)
return ERROR;
/* Регистрация коллбека */
hsyscb.Callback[hsyscb.CallbackInUse] = Callback;
hsyscb.CallbackPeriod[hsyscb.CallbackInUse] = PeriodInMs;
hsyscb.CallbackPrevMs[hsyscb.CallbackInUse] = msTick;
hsyscb.CallbackInUse++;
return OK;
}
/**
* @brief Получение текущего времени в миллисекундах.
* @retval uint32_t Текущее время в миллисекундах
* @note Переполнение происходит через ~49 дней
*/
uint32_t millis(void)
{
return msTick;
}
/**
* @brief Получение текущего времени в микросекундах.
* @retval uint32_t Текущее время в микросекундах
* @note Переполнение происходит через ~71 минуту
*/
uint32_t micros(void)
{
return usTick;
}
/**
* @brief Настройка тактирования АЦП.
* @param ClkSrc Источник тактирования (RCU_PeriphClk_TypeDef)
* @param ClkMHz Желаемая частота АЦП в МГц
* @param state Состояние (ENABLE/DISABLE)
* @retval OperationStatus OK при успехе, ERROR при ошибке
* @note Временное отключает тактирование АЦП во время настройки
*/
OperationStatus rcu_set_clock_adc(RCU_PeriphClk_TypeDef ClkSrc, float ClkMHz, FunctionalState state)
{
uint32_t adc_raw_clock = 0;
float adc_clock_div = 0;
/* Отключение тактирования АЦП для настройки */
RCU_ADCClkCmd(DISABLE);
/* Определение частоты источника тактирования */
switch(ClkSrc)
{
case RCU_PeriphClk_OSEClk:
adc_raw_clock = RCU_GetOSEClkFreq();
break;
case RCU_PeriphClk_OSIClk:
adc_raw_clock = RCU_GetOSIClkFreq();
break;
case RCU_PeriphClk_PLLClk:
adc_raw_clock = RCU_GetPLLClkFreq();
break;
case RCU_PeriphClk_PLLDivClk:
adc_raw_clock = RCU_GetPLLDivClkFreq();
break;
default:
return ERROR;
}
/* Расчет делителя частоты */
adc_clock_div = adc_raw_clock / (ClkMHz * __MHZ);
if(adc_clock_div < 1)
return ERROR;
/* Настройка источника тактирования и делителя */
RCU_ADCClkConfig(ClkSrc, (uint32_t)(adc_clock_div - 1), ENABLE);
/* Включение тактирования, если запрошено */
if(state == ENABLE)
{
RCU_ADCClkCmd(ENABLE);
}
return OK;
}
/**
* @brief Инкремент счетчика миллисекунд.
*/
static inline void millis_inc(void)
{
msTick+=msTickInc;
}
/**
* @brief Инкремент счетчика микросекунд.
*/
static inline void micros_inc(void)
{
usTick+=usTickInc;
}