Вопрос или проблема
Я пытаюсь запустить задачу FreeRTOS на плате STM32F411RE.
void my_task(void *pvParameters)
{
while (1)
{
// Пример:
// Включить светодиод
// задержка
// Выключить светодиод
}
}
int main(void)
{
BaseType_t task_created = xTaskCreate(my_task, "my_task", 1024, NULL, 3, NULL);
if (task_created != pdPASS)
{
// сделать что-то.
}
vTaskStartScheduler();
return 0;
}
Когда вызывается vTaskStartScheduler()
, также вызывается функция ниже, которая находится в timer.c.
static portTASK_FUNCTION( prvTimerTask, pvParameters )
{
TickType_t xNextExpireTime;
BaseType_t xListWasEmpty;
/* Просто чтобы избежать предупреждений компилятора. */
( void ) pvParameters;
#if ( configUSE_DAEMON_TASK_STARTUP_HOOK == 1 )
{
extern void vApplicationDaemonTaskStartupHook( void );
/* Позволяет автору приложения выполнить некоторый код в контексте
* этой задачи в тот момент, когда задача начинает выполняться. Это полезно, если
* приложение включает код инициализации, который будет полезен для
* выполнения после запуска планировщика. */
vApplicationDaemonTaskStartupHook();
}
#endif /* configUSE_DAEMON_TASK_STARTUP_HOOK */
for( ; ; )
{
/* Запросите список таймеров, чтобы узнать, содержит ли он какие-либо таймеры, и если да,
* получите время, в которое истечёт следующий таймер. */
xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );
/* Если таймер истёк, обработайте его. В противном случае заблокируйте эту задачу
* до тех пор, пока таймер не истечёт или не будет получена команда. */
prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );
/* Очистите очередь команд. */
prvProcessReceivedCommands();
}
}
Проблема в том, что когда вызывается эта функция, она зависает в
prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );
с xNextExpireTime = 0 и xListWasEmpty = 1.
Отладка с помощью GDB, если я вхожу в prvProcessTimerOrBlockTask
и иду шаг за шагом, зависания не происходит, и я могу перейти к следующей функции prvProcessReceivedCommands();
, но при выполнении она тоже зависает.
Вот некоторые настройки в FreeRTOSconfig.h
#define configCPU_CLOCK_HZ 100000000UL //100МГц
#define configSYSTICK_CLOCK_HZ (configCPU_CLOCK_HZ)
#define configTICK_RATE_HZ (100)
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1)
#define configIDLE_SHOULD_YIELD 1
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 128)
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 64 * 1024 ) )
Ответ или решение
Причины зависания после вызова планировщика в FreeRTOS на STM32F411RE
Когда вы сталкиваетесь с проблемой зависания после вызова функции vTaskStartScheduler()
в вашей FreeRTOS задаче, это может быть вызвано несколькими факторами. Рассмотрим эти причины более детально, анализируя предоставленный вами код и конфигурацию системы.
1. Отсутствие доступных задач для планирования
Одной из целей vTaskStartScheduler()
является запуск планировщика задач. Если в системе не созданы никакие задачи (или все они стали неподвижными), планировщик будет ожидать исполнения задач, но их не окажется. В вашем случае вы создали одну задачу my_task
, однако необходимо убедиться, что она корректно исполняется в внутреннем цикле.
Рекомендация: Убедитесь, что в задаче my_task
имеются необходимые задержки или ожидания, иначе задача может потреблять все ресурсы CPU, мешая другим задачам (включая задачу таймера) выполняться. Попробуйте добавить вызов vTaskDelay()
или аналогичную функцию для управления временем выполнения:
void my_task(void *pvParameters)
{
while (1)
{
// Включите LED
// ...
vTaskDelay(pdMS_TO_TICKS(1000)); // Задержка в 1000 мс
// Выключите LED
// ...
vTaskDelay(pdMS_TO_TICKS(1000)); // Задержка в 1000 мс
}
}
2. Проблемы с конфигурацией таймера
Параметры вашего конфигурационного файла FreeRTOSconfig.h также играют важную роль. Если задачи не могут быть выполнены из-за конфликта в настройках таймера или их приоритетов, это может привести к зависанию системы.
- Проверьте значение
configTIMER_TASK_PRIORITY
. Оно должно быть ниже, чем приоритет других задач, чтобы обеспечить корректный порядок выполнения. - Убедитесь, что
configUSE_TIMERS
действительно установлено в 1, что позволяет использовать задачи таймера. - Проверьте соответствие
configTICK_RATE_HZ
. Текущая установка в 100 Гц может быть слишком низкой для вашей системы, особенно для быстрого выполнения маломощных задач.
3. Неинициализированные ресурсы
Перед началом выполнения задач убедитесь, что все необходимые ресурсы инициализированы. Это может включать пины GPIO, таймеры и другие элементы, которые используются в задаче.
4. Проблемы с памятью
Если у вашей задачи не хватает памяти, чтобы корректно функционировать, или если установленные значения стеков недостаточны, это может привести к непредвиденным поведениям.
- Убедитесь, что задаче
my_task
выделен достаточный стек (1024 байт может быть недостаточно в зависимости от выполняемых операций). - Проверьте значение
configTOTAL_HEAP_SIZE
, чтобы убедиться, что ваша система имеет достаточно памяти для выполнения всех задач и задач таймера.
5. Анализ ситуации с отладкой
При отладке с использованием GDB и обнаружении (что выполнение не зависает во время пошагового выполнения), это может указывать на проблемы конкурентного доступа к ресурсам, где таймерная задача или другая задача зависят от каких-либо флагов или нарушений ожидания тайминга.
Совет: Используйте средства отслеживания, такие как встроенные отладчики или вывод в консоль, чтобы следить за состоянием приложения и помощью логов выявлять место, где происходит зависание.
Заключение
Надеюсь, что вышеизложенные рекомендации помогут в диагностике и решении проблем с зависанием системы при вызове планировщика в FreeRTOS. Обязательно проверьте все возможные аспекты кода и конфигурации, чтобы выявить возможные баги или неправильные настройки. Успехов в ваших дальнейших разработках на платформе STM32!