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