blob: 67a05c16cb81929879a6e309ac1ca60345241d4c [file] [log] [blame]
.. _module-pw_stream_shmem_mcuxpresso:
==========================
pw_stream_shmem_mcuxpresso
==========================
``pw_stream_shmem_mcuxpresso`` implements the ``pw_stream`` interface for
reading and writing between two different processor cores via shared memory
using the NXP MCUXpresso SDK. It uses the messaging unit module (MU) to signal
data readiness between cores.
Setup
=====
This module requires a little setup:
1. Use ``pw_build_mcuxpresso`` to create a ``pw_source_set`` for an
MCUXpresso SDK.
2. Include the debug console component in this SDK definition.
3. Specify the ``pw_third_party_mcuxpresso_SDK`` GN global variable to specify
the name of this source set.
The name of the SDK source set must be set in the
"pw_third_party_mcuxpresso_SDK" GN arg
Usage
=====
``ShmemMcuxpressoStream`` blocks on both reads and writes, as only one
outstanding buffer can be transferred at a time in each direction. This means a
dedicated thread should be used for both reading and writing. A typical use case
for this class would be as the underlying transport for a pw_rpc network between
cores. Use with the ``pw::rpc::StreamRpcFrameSender`` and
``pw::rpc::StreamRpcDispatcher`` classes.
Interrupt handlers and shared buffers on both cores must be setup before using
this stream. The shared buffer must be mapped as uncacheable on both sides.
As an example on the RT595, we connect the M33 core to the FusionF1 DSP. On the
FusionF1 side, the MU interrupt must be explicitly routed.
Initialization for the M33 Core:
.. code-block:: cpp
// `kSharedBuffer` is a pointer to memory that is shared between the M33 and
// F1 cores, and it is at least `2 * kSharedBufferSize` in size.
ByteSpan read_buffer = ByteSpan{kSharedBuffer, kSharedBufferSize};
ByteSpan write_buffer = ByteSpan{kSharedBuffer + kSharedBufferSize, kSharedBufferSize};
ShmemMcuxpressoStream stream{MUA, read_buffer, write_buffer};
PW_EXTERN_C void MU_A_DriverIRQHandler() {
stream.HandleInterrupt();
}
void Init() {
return stream.Enable();
}
Initialization for the FusionF1 Core:
.. code-block:: cpp
ByteSpan write_buffer = ByteSpan{kSharedBuffer, kSharedBufferSize};
ByteSpan read_buffer = ByteSpan{kSharedBuffer + kSharedBufferSize, kSharedBufferSize};
ShmemMcuxpressoStream stream{MUB, read_buffer, write_buffer};
PW_EXTERN_C void MU_B_IrqHandler(void*) {
stream.HandleInterrupt();
}
void Init() {
// Enables the clock for the Input Mux
INPUTMUX_Init(INPUTMUX);
// MUB interrupt signal is selected for DSP interrupt input 1
INPUTMUX_AttachSignal(INPUTMUX, 1U, kINPUTMUX_MuBToDspInterrupt);
// Disables the clock for the Input Mux to save power
INPUTMUX_Deinit(INPUTMUX);
xt_set_interrupt_handler(kMuBIrqNum, MU_B_IrqHandler, NULL);
xt_interrupt_enable(kMuBIrqNum);
stream.Enable();
}
Read/Write example where each core has threads for reading and writing.
Core 0:
.. code-block:: cpp
constexpr std::byte kCore0Value = std::byte{0xab};
constexpr std::byte kCore1Value = std::byte{0xcd};
void ReadThread() {
while(true) {
std::array<std::byte, 1> read = {};
auto status = stream.Read(read);
if (!status.ok() || status.size() != 1 || read[0] != kCore1Value) {
PW_LOG_WARN("Incorrect value read from core1");
}
}
}
void WriteThread() {
std::array<std::byte, 1> write = {kCore0Value};
while(true) {
stream.Write(write);
}
}
Core 1:
.. code-block:: cpp
void ReadThread() {
while(true) {
std::array<std::byte, 1> read = {};
auto status = stream.Read(read);
if (!status.ok() || status.size() != 1 || read[0] != kCore0Value) {
PW_LOG_WARN("Incorrect value read from core0");
}
}
}
void WriteThread() {
std::array<std::byte, 1> write = {kCore1Value};
while(true) {
stream.Write(write);
}
}