.. _module-pw_stream_shmem_mcuxpresso: ========================== pw_stream_shmem_mcuxpresso ========================== .. pigweed-module:: :name: 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 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 write = {kCore0Value}; while(true) { stream.Write(write); } } Core 1: .. code-block:: cpp void ReadThread() { while(true) { std::array 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 write = {kCore1Value}; while(true) { stream.Write(write); } }