1.. _module-pw_stream_shmem_mcuxpresso: 2 3========================== 4pw_stream_shmem_mcuxpresso 5========================== 6``pw_stream_shmem_mcuxpresso`` implements the ``pw_stream`` interface for 7reading and writing between two different processor cores via shared memory 8using the NXP MCUXpresso SDK. It uses the messaging unit module (MU) to signal 9data readiness between cores. 10 11Setup 12===== 13This module requires a little setup: 14 151. Use ``pw_build_mcuxpresso`` to create a ``pw_source_set`` for an 16 MCUXpresso SDK. 172. Include the debug console component in this SDK definition. 183. Specify the ``pw_third_party_mcuxpresso_SDK`` GN global variable to specify 19 the name of this source set. 20 21The name of the SDK source set must be set in the 22"pw_third_party_mcuxpresso_SDK" GN arg 23 24Usage 25===== 26``ShmemMcuxpressoStream`` blocks on both reads and writes, as only one 27outstanding buffer can be transferred at a time in each direction. This means a 28dedicated thread should be used for both reading and writing. A typical use case 29for this class would be as the underlying transport for a pw_rpc network between 30cores. Use with the ``pw::rpc::StreamRpcFrameSender`` and 31``pw::rpc::StreamRpcDispatcher`` classes. 32 33Interrupt handlers and shared buffers on both cores must be setup before using 34this stream. The shared buffer must be mapped as uncacheable on both sides. 35 36As an example on the RT595, we connect the M33 core to the FusionF1 DSP. On the 37FusionF1 side, the MU interrupt must be explicitly routed. 38 39Initialization for the M33 Core: 40 41.. code-block:: cpp 42 43 // `kSharedBuffer` is a pointer to memory that is shared between the M33 and 44 // F1 cores, and it is at least `2 * kSharedBufferSize` in size. 45 ByteSpan read_buffer = ByteSpan{kSharedBuffer, kSharedBufferSize}; 46 ByteSpan write_buffer = ByteSpan{kSharedBuffer + kSharedBufferSize, kSharedBufferSize}; 47 ShmemMcuxpressoStream stream{MUA, read_buffer, write_buffer}; 48 49 PW_EXTERN_C void MU_A_DriverIRQHandler() { 50 stream.HandleInterrupt(); 51 } 52 53 void Init() { 54 return stream.Enable(); 55 } 56 57Initialization for the FusionF1 Core: 58 59.. code-block:: cpp 60 61 ByteSpan write_buffer = ByteSpan{kSharedBuffer, kSharedBufferSize}; 62 ByteSpan read_buffer = ByteSpan{kSharedBuffer + kSharedBufferSize, kSharedBufferSize}; 63 ShmemMcuxpressoStream stream{MUB, read_buffer, write_buffer}; 64 65 PW_EXTERN_C void MU_B_IrqHandler(void*) { 66 stream.HandleInterrupt(); 67 } 68 69 void Init() { 70 // Enables the clock for the Input Mux 71 INPUTMUX_Init(INPUTMUX); 72 // MUB interrupt signal is selected for DSP interrupt input 1 73 INPUTMUX_AttachSignal(INPUTMUX, 1U, kINPUTMUX_MuBToDspInterrupt); 74 // Disables the clock for the Input Mux to save power 75 INPUTMUX_Deinit(INPUTMUX); 76 77 xt_set_interrupt_handler(kMuBIrqNum, MU_B_IrqHandler, NULL); 78 xt_interrupt_enable(kMuBIrqNum); 79 stream.Enable(); 80 } 81 82Read/Write example where each core has threads for reading and writing. 83 84Core 0: 85 86.. code-block:: cpp 87 88 constexpr std::byte kCore0Value = std::byte{0xab}; 89 constexpr std::byte kCore1Value = std::byte{0xcd}; 90 91 void ReadThread() { 92 while(true) { 93 std::array<std::byte, 1> read = {}; 94 auto status = stream.Read(read); 95 if (!status.ok() || status.size() != 1 || read[0] != kCore1Value) { 96 PW_LOG_WARN("Incorrect value read from core1"); 97 } 98 } 99 } 100 101 102 void WriteThread() { 103 std::array<std::byte, 1> write = {kCore0Value}; 104 while(true) { 105 stream.Write(write); 106 } 107 } 108 109Core 1: 110 111.. code-block:: cpp 112 113 void ReadThread() { 114 while(true) { 115 std::array<std::byte, 1> read = {}; 116 auto status = stream.Read(read); 117 if (!status.ok() || status.size() != 1 || read[0] != kCore0Value) { 118 PW_LOG_WARN("Incorrect value read from core0"); 119 } 120 } 121 122 } 123 124 void WriteThread() { 125 std::array<std::byte, 1> write = {kCore1Value}; 126 while(true) { 127 stream.Write(write); 128 } 129 } 130