STM32CubeMx. Быстрый старт с FreeRTOS для STM32.

Давно не было статей с использованием FreeRTOS на нашем сайте. Что еще более удивительно, если учесть, что в повседневной жизни эта ОС используется регулярно. Так что сегодня без лишних слов и предисловий создадим базовый пример с поддержкой FreeRTOS для STM32. Прошли те времена, когда для включения ОС в свой проект приходилось перетаскивать кучу файлов, некоторые из которых оказывались несовместимы, некоторых просто не хватало… В STM32CubeMx все намного менее интересно и делается в пару кликов. В общем, приступаем!

При работе с FreeRTOS я чаще всего придерживаюсь следующей схемы. Создаются несколько задач (task’ов), каждая из которых вызывается через равные промежутки времени со своим собственным периодом, например:

  • 1 мс
  • 10 мс
  • 50 мс
  • 100 мс

Конкретные значения могут зависеть уже от конкретных целей конкретного проекта. И далее вся работа распределяется по этим task’ам. Соответственно, те действия, которые необходимо выполнять максимально часто вызываются из задачи, период вызова которой равен 1 мс. Например, сохранение значений АЦП для последующей обработки. Другие же действия напротив нужно выполнять намного реже, к примеру, обновлять информацию на дисплее. И в итоге вся программа распределяется по этим временным уровням.

Вот сегодня и реализуем базовый проект для STM32 с поддержкой FreeRTOS и нескольких задач. Пусть task’и будут вызываться каждые 1 мс, 10 мс и 50 мс. По аналогии можно будет легко и быстро добавить и другие.

Запускаем STM32CubeMx. Сразу уточню – не будем подробно погружаться во все нюансы настройки FreeRTOS и рассматривать каждую конкретную опцию, иначе получится не статья, а книга 🙂 Максимально быстрый старт! Если возникнут какие-либо вопросы, смело задавайте их в комментариях или на форуме, я буду рад помочь!

Итак, первым делом активируем FreeRTOS:

Использование FreeRTOS в STM32CubeMx.

Но тут сразу же есть важный нюанс. При использовании FreeRTOS, в качестве базового таймера для HAL рекомендуется выбрать не SysTick (стоит по умолчанию), а другой. Для этого переходим в категорию SYS и меняем SysTick на один из свободных таймеров:

Time base source for HAL.

Поскольку мы уже условились делать базовый проект, то оставляем на этом этапе все настройки FreeRTOS без изменений:

Настройки FreeRTOS для STM32.

Но добавляем наши задачи в разделе Tasks and Queues и задаем их приоритет – Normal:

Создание задачи в STM32CubeMx.

Полностью аналогичным образом добавляем остальные задачи:

Задачи FreeRTOS для микроконтроллера STM32.

Все готово, генерируем, открываем и собираем проект! Видим, что Cube создал наши task’и:

/* creation of Task1ms */
Task1msHandle = osThreadNew(Task1msHandler, NULL, &Task1ms_attributes);

/* creation of Task10ms */
Task10msHandle = osThreadNew(Task10msHandler, NULL, &Task10ms_attributes);

/* creation of Task50ms */
Task50msHandle = osThreadNew(Task50msHandler, NULL, &Task50ms_attributes);

Но сейчас единственное, что связывает эти функции с нашим планом вызывать их через равные промежутки времени – это их название. Так что необходимо доработать непосредственно код функций. И для того, чтобы обеспечить периодичность выполнения task’ов мы будем использовать функцию:

void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement)
  • Первый аргумент хранит значение времени, соответствующее моменту, когда задача была разблокирована в предыдущий раз. При первом вызове функции vTaskDelayUntil() необходимо инициализировать эту переменную текущим значением времени, а в дальнейшем функция сама будет обновлять это значение.
  • Второй аргумент – в нем мы уже задаем нужный нам период. В итоге функция vTaskDelayUntil() заблокирует нашу задачу до момента времени, равного (pxPreviousWakeTime + xTimeIncrement).

Теперь реализуем все на практике. Подключаем:

#include "task.h"

Для task’а, который работает с периодом 10 мс получаем следующее:

void Task10msHandler(void *argument)
{
	/* USER CODE BEGIN Task10msHandler */
	TickType_t xLastWakeTime;
	const TickType_t xFrequency = 10 / portTICK_PERIOD_MS;

	xLastWakeTime = xTaskGetTickCount();
	/* Infinite loop */
	for(;;)
	{
		// Add code here
    
		vTaskDelayUntil(&xLastWakeTime, xFrequency);
	}
	/* USER CODE END Task10msHandler */
}

А непосредственно свой код мы добавляем перед вызовом vTaskDelayUntil(), внутри цикла for(;;). Здесь значение 10 мс задается в строке:

const TickType_t xFrequency = 10 / portTICK_PERIOD_MS;

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

/* USER CODE BEGIN PV */
uint32_t task1msCnt = 0;
uint32_t task10msCnt = 0;
uint32_t task50msCnt = 0;

/* USER CODE END PV */

И итоговый код, например, для task’а 50 мс:

void Task50msHandler(void *argument)
{
	/* USER CODE BEGIN Task50msHandler */
	TickType_t xLastWakeTime;
	const TickType_t xFrequency = 50 / portTICK_PERIOD_MS;

	xLastWakeTime = xTaskGetTickCount();
	/* Infinite loop */
	for(;;)
	{
		// Add code here
		task50msCnt++; 
    
		vTaskDelayUntil(&xLastWakeTime, xFrequency);
	}
	/* USER CODE END Task50msHandler */
}

Вот такой механизм для организации периодических задач в FreeRTOS на контроллере STM32. Давайте соберем проект и проверим, как все это работает. Индикацией для нас будут служить счетчики вызовов task’ов:

Пример использования FreeRTOS для STM32.

Все отрабатывает четко по плану, задачи вызываются с заданной нами периодичностью. И на этом заканчиваем нашу статью, максимально быстрый старт с FreeRTOS для STM32! А в будущих статьях уже будем изучать работу с ОС более подробно!

Ссылка на полный проект – MT_FreeRTOS_Base.

Поделиться!

Подписаться
Уведомление о
guest
0 Комментарий
Inline Feedbacks
View all comments

Присоединяйтесь!

Profile Profile Profile Profile Profile
Vkontakte
Twitter

Язык сайта

Август 2020
Пн Вт Ср Чт Пт Сб Вс
 12
3456789
10111213141516
17181920212223
24252627282930
31  

© 2013-2020 MicroTechnics.ru