After debugging Windows 10 IoT Core & .NetMF nRF24L01P libraries I figured a port to a Wilderness Labs Meadow device shouldn’t be “rocket science”.
I couldn’t source an nRF24L01 feather wing so built a test rig with jumpers

//--------------------------------------------------------------------------------- // Copyright (c) Feb 2020, devMobile Software // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // //--------------------------------------------------------------------------------- namespace devMobile.IoT.nRf24L01 { using System; using System.Text; using System.Threading; using Meadow; using Meadow.Devices; using Meadow.Hardware; public class MeadowApp : App<F7Micro, MeadowApp> { const byte SETUP_AW = 0x03; const byte RX_ADDR_P0 = 0x0A; const byte R_REGISTER = 0b00000000; const byte W_REGISTER = 0b00100000; ISpiBus spiBus; SpiPeripheral nrf24L01Device; IDigitalOutputPort spiPeriphChipSelect; IDigitalOutputPort ChipEnable; public MeadowApp() { ConfigureSpiPort(); SetPipe0RxAddress("ZYXWV"); } public void ConfigureSpiPort() { try { ChipEnable = Device.CreateDigitalOutputPort(Device.Pins.D09, initialState: false); if (ChipEnable == null) { Console.WriteLine("chipEnable == null"); } var spiClockConfiguration = new SpiClockConfiguration(2000, SpiClockConfiguration.Mode.Mode0); spiBus = Device.CreateSpiBus(Device.Pins.SCK, Device.Pins.MOSI, Device.Pins.MISO, spiClockConfiguration); if (spiBus == null) { Console.WriteLine("spiBus == null"); } Console.WriteLine("Creating SPI NSS Port..."); spiPeriphChipSelect = Device.CreateDigitalOutputPort(Device.Pins.D10, initialState: true); if (spiPeriphChipSelect == null) { Console.WriteLine("spiPeriphChipSelect == null"); } Console.WriteLine("nrf24L01Device Device..."); nrf24L01Device = new SpiPeripheral(spiBus, spiPeriphChipSelect); if (nrf24L01Device == null) { Console.WriteLine("nrf24L01Device == null"); } Thread.Sleep(100); Console.WriteLine("ConfigureSpiPort Done..."); } catch (Exception ex) { Console.WriteLine("ConfigureSpiPort " + ex.Message); } } public void SetPipe0RxAddress(string address) { try { // Read the Address width byte[] txBuffer1 = new byte[] { SETUP_AW | R_REGISTER, 0x0 }; Console.WriteLine(" txBuffer:" + BitConverter.ToString(txBuffer1)); /* // Appears to work but not certain it does Console.WriteLine(" nrf24L01Device.WriteRead...SETUP_AW"); byte[] rxBuffer1 = nrf24L01Device.WriteRead(txBuffer1, (ushort)txBuffer1.Length); Console.WriteLine(" nrf24L01Device.WriteRead...SETUP_AW"); */ byte[] rxBuffer1 = new byte[txBuffer1.Length]; Console.WriteLine(" spiBus.ExchangeData...RX_ADDR_P0"); spiBus.ExchangeData(spiPeriphChipSelect, ChipSelectMode.ActiveLow, txBuffer1, rxBuffer1); Console.WriteLine(" rxBuffer:" + BitConverter.ToString(rxBuffer1)); // Extract then adjust the address width byte addressWidthValue = rxBuffer1[1]; addressWidthValue &= 0b00000011; addressWidthValue += 2; Console.WriteLine("Address width 0x{0:x2} - Value 0X{1:x2} - Bits {2} Value adjusted {3}", SETUP_AW, rxBuffer1[1], Convert.ToString(rxBuffer1[1], 2).PadLeft(8, '0'), addressWidthValue); Console.WriteLine(); // Write Pipe0 Receive address Console.WriteLine("Address write 1"); byte[] txBuffer2 = new byte[addressWidthValue + 1]; txBuffer2[0] = RX_ADDR_P0 | W_REGISTER; Array.Copy(Encoding.UTF8.GetBytes(address), 0, txBuffer2, 1, addressWidthValue); Console.WriteLine(" txBuffer:" + BitConverter.ToString(txBuffer2)); Console.WriteLine(" nrf24L01Device.Write...RX_ADDR_P0"); nrf24L01Device.WriteBytes(txBuffer2); Console.WriteLine(); // Read Pipe0 Receive address Console.WriteLine("Address read 1"); byte[] txBuffer3 = new byte[addressWidthValue + 1]; txBuffer3[0] = RX_ADDR_P0 | R_REGISTER; Console.WriteLine(" txBuffer:" + BitConverter.ToString(txBuffer3)); /* // Broken returns Address 0x0a - RX Buffer 5A-5A-5A-5A-59-58 RX Address 5A-5A-5A-59-58 Address ZZZYX Console.WriteLine(" nrf24L01Device.WriteRead...RX_ADDR_P0"); byte[] rxBuffer3 = nrf24L01Device.WriteRead(txBuffer3, (ushort)txBuffer3.Length); */ byte[] rxBuffer3 = new byte[addressWidthValue + 1]; Console.WriteLine(" spiBus.ExchangeData...RX_ADDR_P0"); spiBus.ExchangeData(spiPeriphChipSelect, ChipSelectMode.ActiveLow, txBuffer3, rxBuffer3); Console.WriteLine("Address 0x{0:x2} - RX Buffer {1} RX Address {2} Address {3}", RX_ADDR_P0, BitConverter.ToString(rxBuffer3, 0), BitConverter.ToString(rxBuffer3, 1), UTF8Encoding.UTF8.GetString(rxBuffer3, 1, addressWidthValue)); } catch (Exception ex) { Console.WriteLine("ReadDeviceIDDiy " + ex.Message); } } } }
After lots of tinkering with SPI configuration options and trialing different methods (spiBus vs.SpiPeripheral) I can read and write my nRF24L01 device receive port address
Creating SPI NSS Port... nrf24L01Device Device... ConfigureSpiPort Done... txBuffer:03-00 spiBus.ExchangeData...RX_ADDR_P0 rxBuffer:0E-03 Address width 0x03 - Value 0X03 - Bits 00000011 Value adjusted 5 Address write 1 txBuffer:2A-5A-59-58-57-56 nrf24L01Device.Write...RX_ADDR_P0 Address read 1 txBuffer:0A-00-00-00-00-00 spiBus.ExchangeData...RX_ADDR_P0 Address 0x0a - RX Buffer 0E-5A-59-58-57-56 RX Address 5A-59-58-57-56 Address ZYXWV
I need to investigate why the first byte of the buffer returned by nrf24L01Device.ReadBytes and nrf24L01Device.WriteRead is wrong.