FreeRTOS застрял в osDelay

Я работаю над проектом с использованием STM32F446 с шаблоном, созданным с помощью STM32CubeMX (для инициализации периферийных устройств и промежуточного программного обеспечения, такого как FreeRTOS с интерфейсом CMSIS-V1). У меня есть два потока, которые общаются с помощью почтовых ящиков, но я столкнулся с проблемой: одно из тел потока

void StartDispatcherTask(void const * argument)
{
    mailCommand *commandData = NULL;
    mailCommandResponse *commandResponse = NULL;
    osEvent event;
    for(;;)
    {       
        event = osMailGet(commandMailHandle, osWaitForever);
        commandData = (mailCommand *)event.value.p;

        // Here is the problem
        osDelay(5000);
    }
}

Доходит до задержки, но никогда не выходит. Есть ли проблема с использованием почтового ящика и задержкой в ​​одной ветке? Я пробовал также установить задержку перед for(;;), и это работает.

РЕДАКТИРОВАТЬ: Думаю, я могу попытаться добавить больше деталей к проблеме. Первый поток отправляет письмо определенного типа, а затем ожидает письма другого типа; поток, в котором я получаю сообщение, переходит к первому типу и выполняет некоторый код в зависимости от того, что он получает, а затем отправляет результат как письмо второго типа; иногда бывает так, что он должен ждать с помощью osDelay, и там он перестает работать, но не входит в какой-либо обработчик ошибок


person ArenaLor    schedule 04.05.2019    source источник
comment
Более вероятно, что задержка завершается, и он входит osMailGet(), где ждет вечно (или, по крайней мере, пока что-то не отправит сообщение или его).   -  person Clifford    schedule 05.05.2019
comment
Да, я имел в виду, что почта приходит правильно, потом доходит до задержки, но больше никогда не попадает в osMailGet   -  person ArenaLor    schedule 05.05.2019
comment
Моя точка зрения заключалась скорее в том, как вы это определили наверняка? Ваш код не делает ничего внешне наблюдаемого в этом цикле, поэтому вам придется использовать отладчик и точки останова, чтобы определить это, о чем вы не упомянули. Внешне он всегда будет казаться заблокированным, за исключением крошечного периода, который он назначает commandData (и ничего не делает с ним).   -  person Clifford    schedule 05.05.2019
comment
Да, я на самом деле отлаживаю с помощью Keil v5; Я установил точку останова на osDelay, и она была достигнута, но если я позволю ей запустить снова, я вижу, что она застряла в функции prvCheckTasksWaitingTermination   -  person ArenaLor    schedule 05.05.2019
comment
Код, описанный в редакции, не похож на тот же код. Вы проверили, что код, показанный в вопросе, не работает так же, как код с выполнить некоторый код в зависимости от того, что он получает в нем? СИСТИК работает? Выполняется ли обработчик прерывания SYSTICK? В вопросе должен появиться бит о prvCheckTasksWaitingTermination - вероятно, он актуален. Удаление задач следует считать необычным в системе реального времени - показанный код не показывает, где и почему вы могли это делать.   -  person Clifford    schedule 05.05.2019
comment
Также обратите внимание, что если задача с более высоким приоритетом не блокируется, отложенная задача не будет запланирована после истечения задержки. Поместите точку останова в цикл простаивающей задачи; если ваша система не входит регулярно в цикл ожидания, у вас неправильное поведение и приоритеты задачи. Каждый поток должен быть гарантированно заблокирован, и, как правило, задачам, которые имеют наибольшее или наименее детерминированное время выполнения, следует назначать более низкий приоритет, чем более короткие и более детерминированные.   -  person Clifford    schedule 05.05.2019


Ответы (3)


Я бы предпочел использовать стандартный freeRTOS API. Обертка ARM CMSIS - это чушь.

Кстати, я скорее подозреваю osMailGet(commandMailHandle, osWaitForever);

задержка в этом случае вообще не нужна. Если вы ждете, пока данные в состоянии ЗАБЛОКИРОВАНО, задача не потребляет вычислительную мощность.

Если другие предположения таковы:

  1. Вы приземляетесь на КВ
  2. Вы застряли в переключателе контекста (неправильные приоритеты прерывания)

используйте свой отладчик и посмотрите, что происходит.

person 0___________    schedule 04.05.2019
comment
Первая строка - это мнение, которое лучше опубликовать как комментарий, поскольку оно не является частью ответа. Возможно, это чушь, поэтому существует v2 API, но freeRTOS не лучше, а субъективно хуже (IMO). - person Clifford; 05.05.2019
comment
Я добавил больше деталей к вопросу, так как то, как задержка вызывается в показанном мной коде, является просто упрощенным примером; почта получена правильно, проблема в том, что я больше никогда не доберусь до osMailGet - person ArenaLor; 05.05.2019
comment
@ArenaLor подключите отладчик и посмотрите, где он застрял. Наверное, на переключение контекста, как я уже писал. - person 0___________; 05.05.2019
comment
Но мнение тем не менее, и ему нет места в ответе (точно так же, как вопросы мнения не имеют места в вопросах по SO). Есть причины, по которым можно нуждаться в его использовании (например, переносимость кода) - person Clifford; 05.05.2019
comment
Итак, помимо того факта, что не должно быть ответа, основанного на мнении, для меня это не полная чушь, потому что я мог бы запустить проект без глубоких знаний API freeRTOS и, как сказал @Clifford, переносимость кода (я в любой момент можно было переключиться на Keil RTX) - person ArenaLor; 05.05.2019
comment
@P__J__, пробовал также подключиться к отладчику; Я вижу, что он достигает вызова osDelay, но затем он застревает в функции prvCheckTasksWaitingTermination - person ArenaLor; 05.05.2019
comment
@ArenaLor: У P__J__ есть точка зрения на задержку, однако это плохой дизайн; если задача отправки отправляет сообщения быстрее, чем с интервалом в 5000 тиков, очередь заполняется, а отправитель блокируется. Обычно сообщения должны обрабатываться в режиме реального времени, и вы должны доверять планировщику, а не сомневаться в нем. Вы должны, по крайней мере, выполнить цикл для обработки всех сообщений в очереди, прежде чем вводить задержку, если это вообще необходимо. - person Clifford; 05.05.2019
comment
@Clifford: проблема с настройкой приоритета IRQ довольно сложна для новичков. И я почти уверен, что в вызове SV есть стек. - person 0___________; 05.05.2019
comment
Таким образом, кажется, что это решается увеличением объема стека, выделяемого для двух потоков (со 128 до 512 байтов для каждого). Существуют ли какие-либо принципы для выбора, сколько стека выделять для каждого потока? - person ArenaLor; 06.05.2019
comment
@ArenaLor нет - вы должны сами проанализировать, сколько стека вам нужно - person 0___________; 06.05.2019
comment
Существуют ли какие-либо принципы для выбора, сколько стека выделять для каждого потока? @ArenaLor, да, постарайся угадать, а затем позволь своему коду запуститься и вызвать uxTaskGetStackHighWaterMark() в режиме реального времени, чтобы узнать, сколько ты на самом деле используешь. Вы также можете создать функцию для использования в качестве vApplicationStackOverflowHook() (обратного вызова) для проверки переполнения стека. См. 1) какого размера должен быть стек? freertos.org/FAQMem.html#StackSize, 2) freertos.org/Stacks-and-stack-overflow-checking.html, 3) freertos.org/uxTaskGetStackHighWaterMark.html - person Gabriel Staples; 06.05.2019
comment
@ArenaLor, в нижней части моей ссылки 1 выше: Кроме того, использование стека для всех задач RTOS можно просмотреть сразу с помощью функции uxTaskGetSystemState() API (см. freertos.org/uxTaskGetSystemState.html), и они также рекомендуют прочитать это сообщение в блоге: mcuoneclipse.com/2015/08/21/gnu-static-stack-usage-analysis - person Gabriel Staples; 06.05.2019
comment
Спасибо @GabrielStaples, полезные ссылки! - person ArenaLor; 07.05.2019
comment
Рад помочь! Не забудьте проголосовать за любые вопросы или ответы, которые вы сочтете полезными при переполнении стека, а также за комментарии. Рядом с комментариями, за которые вы хотите проголосовать, есть небольшая стрелка вверх. Это помогает им выделяться, чтобы другие тоже их увидели. Я, например, только что проголосовал за ваше спасибо. - person Gabriel Staples; 07.05.2019
comment
@Clifford - я перевел ваше предложение по поводу отправителя в ответ. - person HelpingHand; 13.04.2020
comment
ArenaLor - вы должны убедиться, что ни одна задача не превышает выделенный стек. В противном случае вся дискуссия бессмысленна, потому что в этом случае RTOS, скорее всего, не сможет поддерживать свои свойства. Помимо (полезного) измерения времени выполнения, упомянутого @GabrielStaples, многие наборы инструментов (в том числе некоторые бесплатные, такие как atollic) предоставляют статическую (автономную) функцию оценки для использования стека графов вызовов функций. - person HelpingHand; 13.04.2020
comment
@P__J__ - Я не согласен с дисквалификацией OSAL, предоставленной ARM CMSIS в целом. Как правильно указал ArenaLor, это может упростить кикстарт. И, что более важно, с моей точки зрения, вы сохраняете переносимость на другие ОС. - person HelpingHand; 13.04.2020

osStatus osDelay (uint32_t миллисекунды)

Значение в миллисекундах определяет количество тактов таймера.

Точное время задержки зависит от фактического времени, прошедшего с момента последнего тика таймера.

При значении 1 система ждет, пока не сработает следующий тик таймера.

=> Вы должны проверить, работает ли тик таймера или нет.

проверьте эту ссылку

person Babajan    schedule 08.05.2019

Как P__J__ указал в предыдущем ответе, вы не должны использовать вызов osDelay() в цикле 1, потому что ваш цикл задач будет ждать при вызове osMailGet() следующего запроса / письма, пока он не будет доставлен в любом случае. Но этот намек привлек мое внимание к другой возможной причине вашего наблюдения, поэтому я открываю новый ответ: 2

Поскольку выполнение цикла прерывается задержкой в ​​5000 тиков - может ли быть, что производитель писем заполняет почтовый ящик быстрее, чем задача потребляет письма? Затем вы должны проверить, обнаружена / обработана ли эта ситуация в контексте производителя.

Если производитель игнорирует возвращаемые значения "очередь заполнена" и отбрасывает сообщения до того, как они были отправлены, система будет обрабатывать только несколько писем каждые 5000 тиков (или она может потерять все, кроме нескольких писем после первого заполнения почтового ящика, если производитель в вашем примере заполняет очередь почтового ящика только один раз). Это может выглядеть так, как будто задача потребителя зависла, даже если основная проблема связана с контекстом производителя (задача / ISR).


1 Вызов osDelay() может помочь вам только в том случае, если вы хотите избежать обработки другого письма в течение 5000 тиков, если письма с запросами создаются быстрее, чем их обрабатывает задача. Но тогда у вас будет другая проблема, и вам следует открыть другой вопрос ...

2 Изменить: Я только что заметил, что Клиффорд уже упоминал об этой опции в одном из своих комментариев к вопросу. Думаю, на этот вариант нужно ответить.

person HelpingHand    schedule 12.04.2020