After porting then debugging Windows 10 IoT Core, .NetMF, Wilderness Labs Meadow and GHI Electronics TinyCLR nRF24L01P libraries I figured yet another port, this time to a nanoFramework powered devices should be low risk.
My initial test rig uses a Netduino 3 Wifi and an Embedded Coolness nRF24 shield as I didn’t need to use jumper wires.
//---------------------------------------------------------------------------------
// Copyright (c) July 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.
//
//---------------------------------------------------------------------------------
#define NETDUINO3_WIFI // nanoff --target NETDUINO3_WIFI --update
namespace devMobile.IoT.nRf24L01.ModuleSPI
{
using System;
using System.Threading;
using System.Diagnostics;
using System.Text;
using Windows.Devices.Gpio;
using Windows.Devices.Spi;
public class Program
{
const byte SETUP_AW = 0x03;
const byte RF_CH = 0x05;
const byte RX_ADDR_P0 = 0x0A;
const byte R_REGISTER = 0b00000000;
const byte W_REGISTER = 0b00100000;
const string P0_Address = "ZYXWV";
#if NETDUINO3_WIFI
private const string SpiBusId = "SPI2";
#endif
public static void Main()
{
#if NETDUINO3_WIFI
// Arduino D7->PD7
int chipSelectPinNumber = PinNumber('A', 1);
#endif
Debug.WriteLine("devMobile.IoT.nRf24L01.ModuleSPI starting");
Debug.WriteLine(Windows.Devices.Spi.SpiDevice.GetDeviceSelector());
try
{
GpioController gpioController = GpioController.GetDefault();
var settings = new SpiConnectionSettings(chipSelectPinNumber)
{
ClockFrequency = 2000000,
Mode = SpiMode.Mode0,
SharingMode = SpiSharingMode.Shared,
};
using (SpiDevice device = SpiDevice.FromId(SpiBusId, settings))
{
Debug.WriteLine("nrf24L01Device Device...");
if (device == null)
{
Debug.WriteLine("nrf24L01Device == null");
}
Thread.Sleep(100);
Debug.WriteLine("ConfigureSpiPort Done...");
Debug.WriteLine("");
Thread.Sleep(500);
try
{
// Read the Address width
Debug.WriteLine("Read address width");
byte[] txBuffer1 = new byte[] { SETUP_AW | R_REGISTER, 0x0 };
byte[] rxBuffer1 = new byte[txBuffer1.Length];
Debug.WriteLine(" nrf24L01Device.TransferFullDuplex...SETUP_AW");
Debug.WriteLine(" txBuffer:" + BitConverter.ToString(txBuffer1));
device.TransferFullDuplex(txBuffer1, rxBuffer1);
Debug.WriteLine(" rxBuffer:" + BitConverter.ToString(rxBuffer1));
// Extract then adjust the address width
byte addressWidthValue = rxBuffer1[1];
addressWidthValue &= 0b00000011;
addressWidthValue += 2;
Debug.WriteLine($"Address width 0x{SETUP_AW:x2} - Value 0X{rxBuffer1[1]:x2} Value adjusted {addressWidthValue}");
Debug.WriteLine("");
// Write Pipe0 Receive address
Debug.WriteLine($"Write Pipe0 Receive Address {P0_Address}");
byte[] txBuffer2 = new byte[addressWidthValue + 1];
byte[] rxBuffer2 = new byte[txBuffer2.Length];
txBuffer2[0] = RX_ADDR_P0 | W_REGISTER;
Array.Copy(Encoding.UTF8.GetBytes(P0_Address), 0, txBuffer2, 1, addressWidthValue);
Debug.WriteLine(" nrf24L01Device.Write...RX_ADDR_P0");
Debug.WriteLine(" txBuffer:" + BitConverter.ToString(txBuffer2));
device.TransferFullDuplex(txBuffer2, rxBuffer2);
Debug.WriteLine("");
// Read Pipe0 Receive address
Debug.WriteLine("Read Pipe0 Receive address");
byte[] txBuffer3 = new byte[addressWidthValue + 1];
txBuffer3[0] = RX_ADDR_P0 | R_REGISTER;
byte[] rxBuffer3 = new byte[txBuffer3.Length];
Debug.WriteLine(" nrf24L01Device.TransferFullDuplex...RX_ADDR_P0");
Debug.WriteLine(" txBuffer:" + BitConverter.ToString(txBuffer3));
device.TransferFullDuplex(txBuffer3, rxBuffer3);
Debug.WriteLine(" rxBuffer:" + BitConverter.ToString(rxBuffer3));
Debug.WriteLine($"Address 0x{RX_ADDR_P0:x2} Address {UTF8Encoding.UTF8.GetString(rxBuffer3, 1, addressWidthValue)}");
Debug.WriteLine("");
// Read the RF Channel
Debug.WriteLine("RF Channel read 1");
byte[] txBuffer4 = new byte[] { RF_CH | R_REGISTER, 0x0 };
byte[] rxBuffer4 = new byte[txBuffer4.Length];
Debug.WriteLine(" nrf24L01Device.TransferFullDuplex...RF_CH");
Debug.WriteLine(" txBuffer:" + BitConverter.ToString(txBuffer4));
device.TransferFullDuplex(txBuffer4, rxBuffer4);
Debug.WriteLine(" rxBuffer:" + BitConverter.ToString(rxBuffer4));
byte rfChannel1 = rxBuffer4[1];
Debug.WriteLine($"RF Channel 1 0x{RF_CH:x2} - Value 0X{rxBuffer4[1]:x2} - Value adjusted {rfChannel1+2400}");
Debug.WriteLine("");
// Write the RF Channel
Debug.WriteLine("RF Channel write");
byte[] txBuffer5 = new byte[] { RF_CH | W_REGISTER, rfChannel1+=1};
byte[] rxBuffer5 = new byte[txBuffer5.Length];
Debug.WriteLine(" nrf24L01Device.Write...RF_CH");
Debug.WriteLine(" txBuffer:" + BitConverter.ToString(txBuffer5));
//device.Write(txBuffer5);
device.TransferFullDuplex(txBuffer5, rxBuffer5);
Debug.WriteLine("");
// Read the RF Channel
Debug.WriteLine("RF Channel read 2");
byte[] txBuffer6 = new byte[] { RF_CH | R_REGISTER, 0x0 };
byte[] rxBuffer6 = new byte[txBuffer6.Length];
Debug.WriteLine(" nrf24L01Device.TransferFullDuplex...RF_CH");
Debug.WriteLine(" txBuffer:" + BitConverter.ToString(txBuffer6));
device.TransferFullDuplex(txBuffer6, rxBuffer6);
Debug.WriteLine(" rxBuffer:" + BitConverter.ToString(rxBuffer6));
byte rfChannel2 = rxBuffer6[1];
Debug.WriteLine($"RF Channel 2 0x{RF_CH:x2} - Value 0X{rxBuffer6[1]:x2} - Value adjusted {rfChannel2+2400}");
Debug.WriteLine("");
}
catch (Exception ex)
{
Debug.WriteLine("Configure Port0 " + ex.Message);
}
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
#if NETDUINO3_WIFI
static int PinNumber(char port, byte pin)
{
if (port < 'A' || port > 'J')
throw new ArgumentException();
return ((port - 'A') * 16) + pin;
}
#endif
}
}
After bit of tinkering with SPI configuration options and checking device.Write vs. device.TransferFullDuplex usage. I can reliably read and write my nRF24L01 device’s receive port address and channel configuration.
devMobile.IoT.nRf24L01.ModuleSPI starting
SPI1,SPI2,SPI3,SPI4
nrf24L01Device Device...
ConfigureSpiPort Done...
Read address width
nrf24L01Device.TransferFullDuplex...SETUP_AW
txBuffer:03-00
rxBuffer:0E-03
Address width 0x03 - Value 0X03 Value adjusted 5
Write Pipe0 Receive Address ZYXWV
nrf24L01Device.Write...RX_ADDR_P0
txBuffer:2A-5A-59-58-57-56
Read Pipe0 Receive address
nrf24L01Device.TransferFullDuplex...RX_ADDR_P0
txBuffer:0A-00-00-00-00-00
rxBuffer:0E-5A-59-58-57-56
Address 0x0A Address ZYXWV
RF Channel read 1
nrf24L01Device.TransferFullDuplex...RF_CH
txBuffer:05-00
rxBuffer:0E-02
RF Channel 1 0x05 - Value 0X02 - Value adjusted 2402
RF Channel write
nrf24L01Device.Write...RF_CH
txBuffer:25-03
RF Channel read 2
nrf24L01Device.TransferFullDuplex...RF_CH
txBuffer:05-00
rxBuffer:0E-03
RF Channel 2 0x05 - Value 0X03 - Value adjusted 2403
The thread '<No Name>' (0x1) has exited with code 0 (0x0).
Done.
Next step is to port my TinyCLR nRF24L01 library which is based on the Techfoonina Windows 10 IoT Core port which is based on .NetMF library by Gralin.