Source: https://freertos.org/RTOS-message-buffer-example.html
Перевод может содержать ошибки. Читайте первоисточник.
Буфер сообщений позволяет передавать отдельные сообщения переменной длинны от обработчика прерываний в задачу, либо из одной задачи в другую. Например, сообщения с длиной 10, 20 и 123 байт могут быть переданы через один и тот же буфер сообщений. В отличие от использования буфера потока, 10-байтное сообщение может быть прочитано только как 10-байтное сообщение, а не как отдельные байты. Буфер сообщений работает поверх буфера потока (иными словами, он использует буфер потока при работе).
Данные передаются буфером сообщений через копирование - данные копируются в буфер отправителем и забираются из буфера при чтении.
В отличие от большинства других коммуникационных примитивов FreeRTOS, буферы потока и, следовательно, буферы сообщений, оптимизированы для сценария с одним отправителем данных, и одним получателем, например для отправки данных из обработчика прерываний в задачу, либо от одного микроконтроллерного ядра к другому в многоядерном контроллере.
Функционал буфера сообщений подключается добавкой к проекту исходного файла FreeRTOS/source/stream_buffer.c.
Реализация буфера сообщений использует уведомления. Следовательно, вызов функций API для работы с буфером сообщений, которые переводят вызывающую задачу в заблокированное состояние, может изменять состояние уведомления и значение в поле уведомления.
ВАЖНОЕ ЗАМЕЧАНИЕ: Уникальность среди объектов FreeRTOS заключается в том, что буфер потока (а также буфер сообщений, т.к. он работает поверх буфера потока) предполагает, что есть только одна задача, которая пишет в буфер потока, и только одна задача, которая читает из буфера потока. Расположение "писателя" и "читателя" в разных задачах или обработчиках прерывания безопасно, но в отличие от большинства других объектов FreeRTOS небезопасно иметь несколько "писателей" либо несколько "читателей". Если всё же в приложении имеется несколько различных "писателей", каждый вызов функций API для записи в буфер (таких как xStreamBufferSend()) необходимо оборачивать в критическую секцию и использовать параметр send block time = 0. Аналогично если имеется несколько "читателей", то каждый вызов функций API для чтения из буфера (таких как xStreamBufferReceive()) необходимо оборачивать в критическую секцию и использовать параметр receive block time = 0.
Исходный файл FreeRTOS/Demo/Common/Minimal/MessageBufferAMP.c содержит хорошо комментированный пример использования буфера сообщений для передачи данных различной длины от одного микропроцессорного ядра другому в многоядерном микроконтроллере. Это усложнённый пример, но механизмы создания буфера сообщений, отправки данных и их получения аналогичны более простым одноядерным сценариям, но в отличие от этого примера, для одноядерных сценариев нет необходимости переопределять макрос sbSEND_COMPLETE().
См. раздел API message buffer пользовательской документации для списка функций API, относящихся к буферам потока. Большая часть страниц содержит также фрагменты кода, показывающие, как эти функции могут быть использованы.
Чтобы позволить буферам управлять сообщениями с различной длиной, перед телом сообщения в буфер записывается его длина (это выполняется внутри функций API). Длина сохраняется в виде переменной типа size_t, которая имеет размер 4 байта для 32-битной архитектуры микроконтроллерного ядра. Следовательно, например, запись 10-байтного сообщения в буфер сообщений будет фактически использовать 14 байт в буфере. Аналогично сообщение размером 100 байт в буфере фактически займёт 104 байта.
xMessageBufferReceive() используется для чтения данных из буфера сообщений из задачи RTOS. xMessageBufferReceiveFromISR() используется для чтения данных из буфера сообщений из обработчика прерываний. xMessageBufferSend() используется для отправки данных в буфер сообщений из задачи RTOS. xMessageBufferSendFromISR() используется для отправки данных в буфер сообщений из обработчика прерываний.
Если задача использует вызов xMessageBufferReceive() с не нулевым временем ожидания для чтения из буфера сообщений, который оказывается пустым на момент вызова, то задача переходит в заблокированное состояние (т.е. не использует процессорное время, и другие задачи могут быть запущены). Задача останется заблокированной до тех пор, пока в данные не появятся в буфере, либо пока не истечёт указанное время ожидания.
Если задача использует вызов xMessageBufferSend() с не нулевым временем ожидания для записи в буфер сообщений, который оказывается заполненным на момент вызова, то задача переходит в заблокированное состояние до тех пор, пока в буфере не появится свободное место, либо пока не истечёт указанное время ожидания.
Поскольку буферы соощений реализованы на базе буферов потока, макросы sbSEND_COMPLETE() и sbRECEIVE_COMPLETE() для буферов сообщений имеют то же смысл, что и для буферов потока.