Блокировка FreeRTOS для нескольких событий / объектов
В примере решения стека UDP/IP здесь предлагается предлагаемое решение для блокировки одной очереди событий.
Каково будет решение для защиты данных, на которые указывает указатель, до тех пор, пока они не будут обработаны задачей, ожидающей очереди.
Скажем, например, что очередь заполнена из ISR. ISR не должен писать в *pvData
если он не был обработан соответствующей задачей. Но поскольку может быть несколько источников событий, очередь, вероятно, должна быть длиннее одного элемента. Должна ли структура быть сделана:
typedef struct IP_TASK_COMMANDS
{
eIPEvent_t eEventType;
SemaphoreHandle_t data_read;
void *pvData;
} xIPStackEvent_t;
С семафором, взятым в ISR и переданным в задаче, которая обрабатывает данные, когда это делается с ним.
2 ответа
Если вы возьмете пример UDP - обычно у вас будет пул буферов (или динамически выделенный буфер), из которого будет получен буфер и передан в DMA. Когда DMA заполняет буфер полученными данными, указатель на буфер попадает в стек UDP - в этот момент только стек UDP знает, где находится буфер, и отвечает за него. В какой-то момент данные в буфере могут быть переданы из стека UDP в приложение, где они могут быть использованы. Затем приложение возвращает буфер в пул (или освобождает выделенный буфер), чтобы он снова был доступен для DMA. Обратное также верно - приложение может выделить буфер, заполненный данными для отправки через стек UDP, функции Tx, где она фактически размещается на проводе, - в этом случае возвращается конечное прерывание Tx буфер в пул.
Короче говоря, есть только одна вещь, которая имеет ссылку на буфер за раз, поэтому проблем нет.
[обратите внимание выше, где говорится, что приложение выделяет или освобождает буфер, который будет находиться внутри API стека UDP/IP, вызываемого приложением, а не непосредственно приложением - это фактически частично, по крайней мере, как наш собственный стек TCP/IP реализованы.]
Вы не хотите, чтобы ваш ISR блокировал и ждал, когда буфер данных станет доступным. Если для вашего ISR уместно просто пропустить обновление и двигаться дальше, когда буфер недоступен, тогда, возможно, семафор имеет смысл. Но ISR не должен блокировать семафор.
Вот альтернатива для рассмотрения. Создайте пул памяти, содержащий несколько буферов данных соответствующего размера. ISR выделяет следующий доступный буфер из пула, записывает в него данные и помещает указатель на него в очередь. Задача читает указатель из очереди, использует данные, а затем освобождает буфер обратно в пул. Если ISR запускается снова до того, как задача использует данные, ISR будет выделять новый буфер, поэтому он не будет перезаписывать предыдущие данные.
Вот еще одно соображение. Очередь FreeRTOS передает элементы копией. Если буфер данных относительно мал, то, возможно, имеет смысл просто передать структуру данных, а не указатель на структуру данных. Если вы передадите структуру данных, то служба очереди создаст копию, чтобы предоставить ее задаче, и ISR сможет обновить свой оригинальный буфер.
Теперь, когда я думаю об этом, использование функции копирования службы очередей может быть проще, чем создание собственного отдельного пула памяти. Я полагаю, что когда вы создаете очередь и указываете длину очереди и размер элемента, служба очереди создает пул памяти, который будет использоваться в очереди.