STM32 HAL SysTick(System timer) как устроен, настройка и управление.
System timer или в простонародье SysTick, системный таймер практически как базовый периферийный таймер имеющий только основу и наделен простой функцией отсчёт импульсов также генерирует прерывание.
Системный таймер как и основная периферия тактируется от AHB шины, на входе имеет предделитель который может иметь два значения это входной сигнал делится на 1 и на 8(STM32F101-107). Состоит из регистра перегрузки(Reload registers) и самого счётчика(Counter registers).
Принцип работы такой же как у любого базового таймера(таймер только с базовыми функциями), регистр Counter(счетчик) считает входящие импульсы до значение которое записано в регистре Reload( регистр перегрузки) после сбрасывается и генерируется прерывание если включено, после начинается отсчёт заново.
Настройка таймера осуществляется после выполнения функции HAL_InitTick которая выполняется в функции HAL_Init(), если код программы сгенерирован в STM32CubeMX то функция задержки HAL_Delay будет работать корректно иначе вам самим придется корректировать некоторые параметры.Функции настройки системного таймера.
void HAL_Delay(uint32_t Delay)- функция которая использует SysTick для своих нужд, предназначена для созданий пауз в программе.
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)- функция настраивает SysTick и включает его прерывание.
void HAL_SuspendTick(void)- функция отключает прерывание SysTick.
void HAL_ResumeTick(void)- функция включает прерывание SysTick.
HAL_StatusTypeDef HAL_SetTickFreq(HAL_TickFreqTypeDef Freq)-Функция изменяет частоту срабатывания прерывания от SysTick.
SET_BIT(REG, BIT)- функция напрямую настраивает регистр SysTick_CTRL, устанавливая нужные биты.
CLEAR_BIT(REG, BIT)- функция напрямую настраивает регистр SysTick_CTRL, сбрасывает нужные биты.
WRITE_REG(REG, VAL)- Функция записывает новое значение в регистры Reload_Value и Counter.
READ_REG(REG)- функция читает данные из регистра Reload_Value и Counter.
Функция включает в коде программы задержку минимальное значение которой миллисекунда, используется функция. совместно с SysTick
void HAL_Delay(uint32_t Delay);
Принимаемое значение от 1 миллисекунды до зависит от частоты
/*Пример настройки задержки 1 секунда*/
HAL_Delay(1000);
Функция настраивает автоматически SysTick включает таймер и его прерывание, если настройку используете сами без STM32CubeMX то придется корректировать значение переменной библиотеки HAL SystemCoreClock( частота работы AHB шины или контроллера если предделитель AHB=1).
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority);
Функция принимает приоритет прерывания для SysTick
Если установлена 4 группа для прерываний функцией
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
То значение может быть
от 0 до 15, устанавливается обычно 15
/*Пример настройки*/
SystemCoreClock = 8000000;
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
HAL_InitTick(15);
Функция отключает прерывание от SysTick тем самым прекращает работу прерываний таймера, функция HAL_Delay работать больше не будет.
void HAL_SuspendTick(void);
/*Пример использования*/
HAL_SuspendTick();
Функция включает прерывание от SysTick тем самым возобновляет работу прерываний таймера, функцию HAL_Delay можно использовать. Данная функция используется если отключался таймер функцией HAL_SuspendTick().
void HAL_ResumeTick(void);
/*Пример использования*/
HAL_ResumeTick();
Функция изменяет частоту срабатывания прерывания от SysTick, по умолчанию таймер настроен на частоту 1KHz для отработки задержки от функции HAL_Delay в 1 миллисекунду. Перед использование данной функции измените значение переменной библиотеки HAL uwTickPrio = 15; которая устанавливает приоритет прерывания.
HAL_StatusTypeDef HAL_SetTickFreq(HAL_TickFreqTypeDef Freq);
Функция принимает значение частоты в KHz
/*Пример настройки на частоту 1KHz*/
uwTickPrio = 15;
HAL_SetTickFreq(1);
Функция которая устанавливает биты управления в регистре контроля SysTick.
SET_BIT(REG, BIT);
Функция принимает два параметра:
регистр контроля SysTick->CTRL
и маски для управления
SysTick_CTRL_CLKSOURCE_Msk-установит предделитель таймера в 1
SysTick_CTRL_TICKINT_Msk-включает прерывание
SysTick_CTRL_ENABLE_Msk-включает таймер
/*Пример*/
SET_BIT( SysTick->CTRL, SysTick_CTRL_ENABLE_Msk);
Функция которая сбрасывает биты управления в регистре контроля SysTick.
CLEAR_BIT(REG, BIT);
Функция принимает два параметра:
регистр контроля SysTick->CTRL
и маски для управления
SysTick_CTRL_CLKSOURCE_Msk-установит предделитель таймера в 8
SysTick_CTRL_TICKINT_Msk-отключает прерывание
SysTick_CTRL_ENABLE_Msk-отключает таймер
/*Пример*/
CLEAR_BIT( SysTick->CTRL, SysTick_CTRL_ENABLE_Msk);
Функция записывает новое значение в регистры Reload_Value и Counter.
WRITE_REG(REG, VAL);
Функция принимает регистр REG это
SysTick->LOAD-Reload Value( регистр перегрузки регистра счётчика)
SysTick->VAL-Current Value( регистр счётчик)
и второй параметр который принимает функция это значение VAL
которое может быть от 0 до 16777215
/*Пример*/
WRITE_REG( SysTick->LOAD, 10000);
Функция читает значение из регистров Reload_Value и Counter.
READ_REG(REG);
Функция принимает регистр REG это
SysTick->LOAD-Reload Value( регистр перегрузки регистра счётчика)
SysTick->VAL-Current Value( регистр счётчик)
Возвращает значение нужного регистра
/*Пример*/
uint32_t val = READ_REG(SysTick->VAL);
Прерывание SysTick как настроить.
В файле stm32f1xx_it.c вставлен функция обработки прерывания, которую можно переместить в тело вашей программы для удобства, но не забудьте тогда удалить в файле stm32f1xx_it.c.
Прерывание не нужно включать в NVIC регистре просто необходимо дать приоритет данному прерыванию функцией описанной выше.
Пример программы.
В примере кода показано как самому настроить SysTick самостоятельно или использовать функцию HAL_Init() или HAL_InitTick(15U).
/*ProgCont.ru*/
#include "main.h"
uint32_t count;
int main(void)
{
// HAL_Init();
// HAL_InitTick(15U);
SystemCoreClock = 8000000;//Частота контроллера
uwTickFreq = 1;//Задержка в миллисекундах
count = SystemCoreClock / (1000U / uwTickFreq);//Значение для регистра Reload
WRITE_REG( SysTick->LOAD, count);
HAL_NVIC_SetPriority(SysTick_IRQn, 15U, 0U);
SET_BIT( SysTick->CTRL, SysTick_CTRL_CLKSOURCE_Msk);//Устанавливаем предделитель в 1
SET_BIT( SysTick->CTRL, SysTick_CTRL_TICKINT_Msk);//Включаем прерывание
SET_BIT( SysTick->CTRL, SysTick_CTRL_ENABLE_Msk);//Включаем таймер
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
HAL_NVIC_DisableIRQ(SysTick_IRQn);
while (1)
{
HAL_GPIO_TogglePin( GPIOC, GPIO_PIN_13); HAL_Delay(500);
}
}
void SysTick_Handler(void)
{
HAL_IncTick();//Внутрения функция HAL_Delay
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line){}
#endif /* USE_FULL_ASSERT */