On this page:
-
Introduction
-
Getting started
-
Sizing a Message Buffer
-
Blocking Reads and Writes
-
Send and Receive Complete Macros (for multicore use)
Message buffers allow variable length discrete messages to be passed from an interrupt service
routine to a task, or from one task to another task. For example, messages of
length 10, 20 and 123 bytes can all be written to, and read from, the same
message buffer. Unlike when using a stream buffer,
a 10 byte message can only be read out as a 10 byte message, not as individual
bytes. Message buffers are built on top of stream buffers (that is, they use
the stream buffer implementation).
Data is passed through a message buffer by copy - the data is copied into the
buffer by the sender and out of the buffer by the read.
Unlike most other FreeRTOS
communications primitives, stream buffers, and therefore also message buffers,
are optimised for single reader single writer
scenarios, such as passing data from an interrupt service routine to a task, or
from one microcontroller core to another on a dual core CPU.
Message buffer functionality is enabled by including the FreeRTOS/source/stream_buffer.c
source file in the build.
The message buffer implementation uses
direct to task notifications. Therefore, calling a message buffer API function that places
the calling task into the Blocked state can change the calling task's notification
state and value.
IMPORTANT NOTE: Uniquely among FreeRTOS objects, the
stream buffer implementation (so also the message buffer
implementation, as message buffers are built on top of stream buffers) assumes there is only one task or
interrupt that will write to the buffer (the writer), and only one task or
interrupt that will read from the buffer (the reader). It is safe for the
writer and reader to be different tasks or interrupts, but, unlike other
FreeRTOS objects, it is not safe to have multiple different writers or
multiple different readers. If there are to be multiple different writers
then the application writer must place each call to a writing API function
(such as xStreamBufferSend()) inside a
critical section and use a send block time of 0. Likewise, if there
are to be multiple different readers then the application writer must place
each call to a reading API function (such as xStreamBufferReceive()) inside a
critical section and use a receive block time of 0.
The FreeRTOS/Demo/Common/Minimal/MessageBufferAMP.c source file
provides a heavily commented example of how to use a message buffer to pass variable
length data from one MCU core to another on a multi-core MCU. That is quite an
advanced scenario, but the mechanism for creating, sending to and receiving from
the message buffer is the same in simpler single core scenarios where, unlike
in the demo, it is not necessary
to override the sbSEND_COMPLETE() macros.
See the message buffer section of the
user documentation for a list of message buffer
related API functions, in many cases including code snippets that demonstrate
the functions being used.
To enable message buffers to handle variable sized messages
the length of each message is written into the message buffer before the message
itself (that happens internally with the FreeRTOS API functions). The length
is stored in a variable of type size_t, which is typically 4-bytes on a 32-byte
architecture. Therefore, as an example, writing a 10 byte message into a message
buffer will actually consume 14 bytes of buffer space. Likewise writing a 100
byte message into a message buffer will actually store 104 bytes of buffer space.
xMessageBufferReceive()) is used to read
data from a message buffer from an RTOS task.
xMessageBufferReceiveFromISR()) is
used to read data from a message buffer from an interrupt service routine (ISR).
xMessageBufferSend()) is used to send
data to a message buffer from an RTOS task.
xMessageBufferSendFromISR()) is
used to send data to a message buffer from an interrupt service routine (ISR).
If a non zero block time is specified when a task uses xMessageBufferReceive() to
read from a message buffer that happens to be empty the task will be placed into
the Blocked state (so it is not consuming any CPU time and other tasks can run)
until either data becomes available in the message buffer, or the block time
expires.
If a non zero block time is specified when a task uses xMessageBufferSend() to
write to a message buffer that happens to be full the task will be placed into
the Blocked state (so it is not consuming any CPU time and other tasks can run)
until either space becomes available in the message buffer, or the block time
expires.
As message buffers are built on stream buffers the sbSEND_COMPLETE() and
sbRECEIVE_COMPLETE() macros behave exactly as described on the
page that describes stream buffers.
Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.
|