Отладка FreeRTOS в Eclipse, TrueStudio и CubeIDE





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

Первым делом установим плагин, я буду это делать в CubeIDE (в Eclipse и TrueStudio процесс точно такой же).

Переходим в меню Help и выбираем там пункт Install New Software



В появившемся окне нажимаем кнопочку Add, и в следующем окне вписываем какое-нибудь имя и адрес репозитория с которого будет скачан плагин…


http://freescale.com/lgfiles/updates/Eclipse/KDS


Нажимаем кнопку Add и попадаем в следующее окно где нужно поставить галочки как на картинке…




Нажимаем Next, попадаем в следующее окно где тоже жмём Next, и в следующем окне соглашаемся с лицензией…




Жмём Finish и ждём появления окна с предложением перезапустить IDE…




После рестарта всё будет готово к работе. На этом установка закончена.



Теперь открываем проект с FreeRTOS, идём в файл FreeRTOSConfig.h, и включаем…

#define configGENERATE_RUN_TIME_STATS  1

#define configUSE_TRACE_FACILITY  1

#define configRECORD_STACK_HIGH_ADDRESS  1


Ещё может потребоваться отключить совместимость со старыми версиями…

#define configENABLE_BACKWARD_COMPATIBILITY 0

У меня работает и так и так.


Если работаете в Кубе, тогда включите (Enabled) это в разделе Config parameters, там такие же названия только без приставки «config».


Далее пересобираем проект и запускаем отладку. IDE переключится на перспективу отладки, в меню которой появился новый пункт — FreeRTOS



Тыкаем по очереди все четыре пункта, и у нас появятся соответствующие вкладки…


Если внимательно присмотреться, то можно разглядеть логотип компании NXP, которая и разработала этот плагин. Это так, к слову, а к делу не имеет отношения.



Task List

Выбираем вкладку Task List. Сейчас там ничего нет, равно как в других вкладках. Чтоб данные появились нужно запустить программу   и поставить на паузу



TCB — Task Control Block.

Task Name — имя прописанное при создании задачи.

Task Handle — адрес задачи.

Task State — состояние задачи.

Priority — приоритет задачи.

Stack Usage — сколько задача использовала стека/размер стека задачи. Данные указаны в байтах, а не в машинных словах.

Event Object — объекты (семафоры, очереди, мьютексы) связанные с задачей. Чтоб они отображались им нужно присвоить имена. Делается это с помощью функции vQueueAddToRegistry() сразу после создания (семафора, очереди или мьютекса)

Semaphore_hcs301 = xSemaphoreCreateBinary();

if(Semaphore_hcs301 == NULL)
{
	My_Error_Handler(1);
}

vQueueAddToRegistry(Semaphore_hcs301, "sem_hcs301"); // присвоили имя семафору

Помимо этого нужно чтоб значение configQUEUE_REGISTRY_SIZE было равным (или большим) количеству очередей, семафоров и мьютексов.


Runtime — время выполнения задач. Сейчас там жёлтенькие значки сообщающие о том, что это не настроено, а вот чтоб заработало нужно немножко поколдовать.

Первым делом нужно настроить какой-нибудь таймер для отсчёта микросекунд…



Предделитель указан исходя из того, что системная частота равна 72МГц. Этот таймер будет просто тикать, а FreeRTOS будет смотреть сколько он насчитал микросекунд.


Далее, предполагается что в настройках FreeRTOS в Кубе вы выбрали CMSIS_V2…




У вас должен был создаться файл freertos.c, а в нём должны быть вот такие функции…




Объявим в этом файле переменную структуры таймера как extern…

/* USER CODE BEGIN Variables */
extern TIM_HandleTypeDef htim3;
/* USER CODE END Variables */

Укажите свой таймер.

В первую функцию добавим запуск таймера…

__weak void configureTimerForRunTimeStats(void)
{
	HAL_TIM_Base_Start(&htim3);
}


А во вторую вот такой код…

__weak unsigned long getRunTimeCounterValue(void)
{
	static unsigned long counter = 0;

	counter += __HAL_TIM_GET_COUNTER(&htim3);
	__HAL_TIM_SET_COUNTER(&htim3, 0);

	return counter;
}

Переменная counter будет накапливать количество тиков (микросекунд), а FreeRTOS забирать их. Это происходит без нашего участия.

Если хотите, можете перенести эти функции куда вам удобнее, без атрибута __weak. Помните что при перегенерации проекта в Кубе, это всё затрётся.


На этом настройка закончена и можно посмотреть что получилось. Однако есть один нюанс, если у вас включена оптимизация, то вы опять увидите всё те же жёлтенькие значки.

Можно конечно отключить оптимизацию, это делается в свойствах проекта…


… но лучше всё таки устранить эту проблему.

Тут дело вот в чём, в недрах FreeRTOS есть переменная, которая отвечает за наш счётчик микросекунд, а компилятор почему-то оптимизирует её и тем самым портит всю «малину». Чтобы это дело исправить, нужно найти в файле tasks.c вот такие сроки…



Конкретно нас интересует переменная ulTotalRunTime, вот её то и оптимизирует компилятор, а чтоб запретить ему это делать, надо добавить специальный атрибут чтоб получилось так…

#if ( configGENERATE_RUN_TIME_STATS == 1 )

	PRIVILEGED_DATA static uint32_t ulTaskSwitchedInTime = 0UL;	
	PRIVILEGED_DATA static
	#ifdef __GNUC__
	__attribute__((used))
	#endif
	uint32_t ulTotalRunTime = 0UL;

#endif

Опять же, помните что при перегенерации проекта в Кубе, это затрётся.

Этот всё касается компилятора GNU, как поведут себя другие я не знаю.


Ну, а теперь компилируем проект, жмём дебаг и смотрим что получилось…



HEX значение, это количество микросекунд, которое потратила каждая из задач с момента старта программы до того как мы нажали паузу.

Программа у меня работала около 10 секунд, из них задача logger работала 85373 микросекунд, то есть она почти ничего не делала, только вывела в УАРТ несколько строк и вошла в состояние Blocked.

Задача hcs301 вообще ничего не делала и ждала семафора, поэтому работала всего 13 микросекунд.

Задача defaultTask тоже почти ничего не делала, в ней просто стояла пауза osDelay(1).

Больше всех работала задача IDLE, то есть можно сказать что программа практически ничего не делала.


Теперь загрузим задачу defaultTask так чтоб она постоянно работала…

void StartDefaultTask(void *argument)
{
  for(;;)
  {
    for(volatile uint32_t i = 0; i < 10000000; i++)
    {
    	__NOP();
    }

    //osDelay(1);
  }
}


И в результате получим совсем другую картину…



Из-за нашей ужасной конструкции задача defaultTask съела почти всё время.



Queue List


Различная информация об очередях, семафорах и мьтексах. Думаю тут и без комментариев всё понятно. Чтоб они отображались, нужно присвоить им имена как написано выше.



Timer List

То же самое что и выше, только о программных таймерах. У меня там ничего не настроено поэтому показать нечего.



Heap Usage


Тут подробно об использовании «кучи», опять же думаю что объяснять нечего. Вначале общие данные — сколько использовано, сколько всего, а ниже как её раздербанили задачи.



Собственно это всё. Информацию я взял тут, там описываются ещё какие-то методы отладки, но я не стал разбираться.


Всем спасибо


Телеграм-чат istarik

Телеграм-чат STM32


  • 0
  • 17267
Поддержать автора


Telegram-чат istarik

Задать вопрос по статье
Telegram-канал istarik

Известит Вас о новых публикациях






Комментарии (0)

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.