Переполнение при отсчете времени в STM32Cube

Ранее я писал об отсчете времени в STM32Cube.

STM32Cube считает время в миллисекундах. Время хранится в беззнаковой целочисленной 32-битной переменной:

static __IO uint32_t uwTick;

Это означает, что через 49 суток 17 часов 2 минуты 47 секунд и 295 миллисекунд произойдет переполнение этой переменной.

Хорошо, если устройство не может так долго работать, например, гарантировано сядет батарейка. Но, что если устройство должно работать непрерывно месяцами?

Время используется библиотекой в операциях ввода/вывода для организации таймаутов. Кроме того, библиотека предоставляет функцию задержки HAL_Delay().

Если переполнение обрабатывается неправильно, то мы получим неправильные таймауты и задержки.

Посмотрим, на код, отвечающий за обработку времени:

файл stm32***_it.c:

void SysTick_Handler(void)
{
  HAL_IncTick();
}

файл stm32***_hal.c:

static __IO uint32_t uwTick;

__weak void HAL_IncTick(void)
{
  uwTick++;
}

__weak uint32_t HAL_GetTick(void)
{
  return uwTick;
}

__weak void HAL_Delay(__IO uint32_t Delay)
{
  uint32_t tickstart = 0;
  tickstart = HAL_GetTick();
  while((HAL_GetTick() - tickstart) < Delay)
  {
  }
}

Обработчик прерывания SysTick_Handler() вызывается каждую миллисекунду, и вызывает функцию HAL_IncTick(), которая просто увеличивает uwTick на единицу (инкрементирует). Функция HAL_GetTick() возвращает текущее время в миллисекундах; эта функция обильно используется библиотекой следующим образом:

uint32_t tickstart = HAL_GetTick();
...
if((HAL_GetTick()-tickstart) >= Timeout)
{ ... }

Операция сравнения времени довольно проста. Аналогичная операция используется в функции HAL_Delay().

Видите обработку переполнения? И я не вижу. А она есть.

Рассмотрим функцию HAL_Delay(). Для начала ситуацию без переполнения.

Допустим:

Delay = 100,
tickstart = 1000.

Разница

HAL_GetTick()-tickstart

будет расти от 0 до 100. Цикл будет прерван, когда HAL_GetTick() вернет 1100:

1100 - 1000 = 100

100 < 100 = ложь,

Теперь рассмотрим ситуацию с переполнением.

Допустим:

Delay = 100,
tickstart = 4294967290
.

Максимальное число в беззнаковой 32-битной переменной равно 4294967295. То есть до переполнения остается всего 5 инкрементов. При 6-м инкременте HAL_GetTick() вернет 0.

Что тогда вернет операция

HAL_GetTick()-tickstart

то есть, что будет если из 0 вычесть 4294967290?

Обе переменные беззнаковые и целочисленные. И операция вычитания вернет 6. А дальше, когда HAL_GetTick() возвратит 1, операция вычитания вернет 7.

То есть разница между текущим временем и tickstart все время будет расти, как и в нормальной ситуации. Функция задержки отработает правильно.

Важно, что такое поведение стандартизировано и должно реализовываться любым компилятор C и C++. Можете ознакомиться с обсуждением этого вопроса на Stack Overflow.

Что касается двойного переполнения, то оно никак не влияет, потому что библиотека не позволяют делать настолько большие задержки и таймауты.

Вывод

Обработка времени в библиотеке STM32Cube происходит корректно, несмотря на то, что переменная uwTick, хранящая время, может переполнится.

Реклама

Автор

Дмитрий Бравиков

Инженер. Электронщик. Программист.

Переполнение при отсчете времени в STM32Cube: 3 комментария

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход /  Изменить )

Google photo

Для комментария используется ваша учётная запись Google. Выход /  Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход /  Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход /  Изменить )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.