FreeRTOS: зачем вызывать метод taskYIELD_FROM_ISR () в isrHandler - PullRequest
2 голосов
/ 30 октября 2019

Я пытаюсь понять, почему пользователь должен вызывать метод taskYIELD_FROM_ISR() и почему он не вызывается автоматически ОСРВ в рамках метода xStreamBufferSendFromISR.

Мой вопрос относится к FreeRTOS_Manual p. 369.

/* A stream buffer that has already been created. */
StreamBufferHandle_t xStreamBuffer;

void vAnInterruptServiceRoutine( void ) {
  size_t xBytesSent;
  char *pcStringToSend = "String to send";
  BaseType_t xHigherPriorityTaskWoken = pdFALSE;

  /* Attempt to send the string to the stream buffer. */
  xBytesSent = xStreamBufferSendFromISR(xStreamBuffer,(void *) pcStringToSend,strlen( pcStringToSend),&xHigherPriorityTaskWoken);

  if(xBytesSent != strlen(pcStringToSend)){
    /* There was not enough free space in the stream buffer for the entire string to be written, ut xBytesSent bytes were written. */
  }

  /* 
    If xHigherPriorityTaskWoken was set to pdTRUE inside xStreamBufferSendFromISR() then a    
    task that has a priority above the priority of the currently executing task was unblocked 
    and a context switch should be performed to ensure the ISR returns to the unblocked task. 
    In most FreeRTOS ports this is done by simply passing xHigherPriorityTaskWoken into 
    taskYIELD_FROM_ISR(), which will test the variables value, and perform the context switch 
    if necessary. Check the documentation for the port in use for port specific instructions. 
  */

  taskYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

Мое понимание сценария

Предварительные условия

  • Есть две задачи
    • Task1 (высокий приоритет) и Task2 (низкий приоритет)
  • Task1 находится в заблокированном состоянии, ожидая входной поток streamBuffer
  • Task2 находится в рабочем состояниии прерывается с vAnInterruptServiceRoutine

в пределах ISR

  • Метод ISR вызывает xStreamBufferSendFromISR()
  • Этот вызов означаетто, что заблокированное состояние задачи 1 переходит в состояние готовности

случай A Если метод ISR возвращается сейчас, планировщик не будет вызываться, и задача 2 будет выполняться допериод временного интервала закончился, и затем планировщик переключается на высокий предшествующий Задача 1.

Случай B Если метод ISR наконец вызывает taskYIELD_FROM_ISR(xHigherPriorityTaskWoken);, планировщик будет вызван и после возвратаISR, Task1 будет работать вместо Task2.

Вопросы

  1. Правильно ли, thв Task2 будет выполняться до тех пор, пока не истечет период времени или не появится другой тигр для переключения задач?
  2. Почему метод taskYIELD_FROM_ISR() не вызывается автоматически ОСРВ при вызове xStreamBufferSendFromISR()?

Ответы [ 2 ]

2 голосов
/ 07 ноября 2019
  1. Да, без вызова taskYIELD_FROM_ISR планировщик задает контекст для Task1 на следующем запланированном тике. Это можно проверить с помощью Segger SystemView. uartPrintTask блокирует семафор, а затем печатает данные из буфера. Обратите внимание на длительную задержку между тем, когда uartPrintTask «готов» и когда он «работает». Эта задержка является переменной - хотя она никогда не длится дольше, чем 1 мс (частота тиков в примере) enter image description here

Теперь, тот же самый пример с taskYIELD_FROM_ISR, добавленным наконец ISR. uartPrintTask последовательно выполняется после ISR enter image description here 2. FreeRTOS не может автоматически вызвать что-либо из ISR. У вас есть полный контроль над всеми прерываниями. taskYIELD_FROM_ISR должен быть помещен в конце вашей реализации ISR (но вы, возможно, сделали вызов xStreamBufferSendFromISR в любом месте ISR).

Одна из прекрасных особенностей FreeRTOS (на мой взгляд)что он ничего не угоняет и дает тонны гибкости. У вас могут быть прерывания, которые выполняются полностью «под» ОСРВ - FreeRTOS не нужно ничего знать о них. Не автоматический вызов taskYIELD_FROM_ISR является еще одним примером такой гибкости (на мой взгляд).

Из руководства SafeRTOS :

Вызов либо xQueueSendFromISR (), либоxQueueReceiveFromISR () внутри подпрограммы обработки прерываний может потенциально заставить задачу выйти из заблокированного состояния, что затем требует переключения контекста, если разблокированная задача имеет более высокий приоритет, чем прерванная задача. Переключение контекста выполняется прозрачно (в рамках функций API), когда xQueueSend () или xQueueReceive () вызывают задачу с более высоким приоритетом, чем вызывающая задача, для выхода из заблокированного состояния. Такое поведение желательно из задачи, но не из процедуры обработки прерывания. Следовательно, xQueueSendFromISR () и xQueueReceiveFromISR () вместо того, чтобы сами выполнять переключение контекста, вместо этого возвращают значение, указывающее, требуется ли переключение контекста. Если требуется переключение контекста, разработчик приложения может использовать taskYIELD_FROM_ISR () для выполнения переключения контекста в наиболее подходящее время, обычно в конце обработчика прерываний. См. «XQueueSendFromISR ()» на стр. 69 и «xQueueReceiveFromISR ()» на стр. 71, в которых описаны функции xQueueSendFromISR () и xQueueReceiveFromISR () соответственно для получения дополнительной информации.

0 голосов
/ 31 октября 2019
  • 1) Я так думаю
  • 2) Я не совсем уверен в этом. Я думаю, что это сделано для быстрого прерывания и для снижения издержек при переключении контекста. Таким образом, вы можете переключать контекст или нет, в зависимости от того, какое время отклика вам нужно.
...