I used an NRF24L01+ attached to an Intel Galileo Gen2 to do an RF channel scan in an effort to identify a “good” choice for a channel that will best avoid interference. The program repeatedly changes channel and monitors the Received Power Detect Bit (Register 9). The program ran for and hour and counted up the number of times the RPD bit was 1 for each of the 128 channels and produced an output like this:
0 0 0 0 0 0 1 0 0 0 1 0 0 1 1 0
1 0 0 0 1 0 1 1 0 2 1 0 0 0 0 1
0 0 0 0 0 0 0 1 0 1 1 0 1 0 0 0
0 0 1 0 0 1 3 6 3 2 4 9 4 7 12 5
4 7 2 3 7 5 1 3 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Each step across the output array represents a 1MHz step in frequency. The start frequency is 2400MHz. The value ’12’ occurs at a frequency of 2462MHz. This corresponds to Wifi Channel 11 – a fact confirmed by doing a Wifi Channel scan on my laptop which showed two Wifi access points operating at this frequency.
It is worth noticing that there is not much happening beyond 2471MHz. This is probably because Wifi stops around here (at least in Europe). So is this the answer – simply stay outside the Wifi bands? In Europe, the Wifi bands range from 2412MHz to 2472MHz so maybe the best NRF24L01 channels are less than 12 and greater than 72. Time will tell….
Code is below (node.js)
// NRF24L01+ demo in javascript for the Intel Galileo Gen 2 // Author: Frank Duignan. // Updates posted on http://ioprog.com and http://eleceng.dit.ie/frank var PAYLOAD_LENGTH=10 var SOURCE_ADDRESS=([8,0,5,8,6]); var DESTINATION_ADDRESS=([0x0a,1,1,1,4]); /******* Low level setup (configure I/O etc *******/ var m=require('mraa'); console.log('MRAA version: ' + m.getVersion()); // configure SPI for 1MHz operation var SPI=new m.Spi(0); SPI.frequency(1000000); // Set up CE and CSN pins for the NRF24L01 // These will be directly controlled by software NOT the SPI hardware var CEPin=new m.Gpio(9); var CSNPin=new m.Gpio(8); CEPin.dir(m.DIR_OUT); CSNPin.dir(m.DIR_OUT); CEPin.write(0); CSNPin.write(1); // Global variable that is updated during each SPI transaction var NRFStatus; // NRF Functions follow function NRFinit() { NRFWriteRegister(0,0); // Clear out config NRFWriteRegister(1,3); // enable auto ack in P0 and P1 NRFWriteRegister(4,0x24); // 750us between retries, 4 retries NRFWriteRegister(2,3); // enable data pipe 0 and 1 NRFWriteRegister(3,3); // 5 byte addressing NRFWriteRegister(0x05,5); // select channel 5 NRFWriteRegister(0x06,0x06); // select 1Mbps, maximum power NRFWriteRegister(0x07,0x70); // clear status flags NRFWriteRegister(0x11,0); // Auto ack in pipe 0 NRFWriteRegister(0x12,PAYLOAD_LENGTH); // set payload length NRFWriteCE(1); NRFEnableRXMode(); // start listening } function delay(howlong) { howlong = howlong / 2; // yields approx 1us timebase while(howlong > 0) { howlong = howlong -1 ; } } function NRFWriteCE(Value) { if (Value) CEPin.write(1) else CEPin.write(0) } function NRFWriteCSN(Value) { if (Value ) CSNPin.write(1); else CSNPin.write(0); } function transferSPI(data) { return SPI.writeByte(data); } function NRFReadRegister(RegNum) { var ReturnValue=0; NRFWriteCSN(0); if (RegNum < 0x20) { NRFStatus = transferSPI(RegNum); // update status after CSN goes low ReturnValue = transferSPI(0xff); // Send dummy byte to generate clocks } else { ReturnValue = -1; } NRFWriteCSN(1); return ReturnValue; } function NRFWriteRegister(RegNum, Value) { var ReturnValue=0; NRFWriteCSN(0); if (RegNum < 0x20) { NRFStatus = transferSPI(0x20+RegNum); // update status after CSN goes low ReturnValue = transferSPI(Value); // Write byte to target } else { ReturnValue = -1; } NRFWriteCSN(1); return ReturnValue; } function NRFFlushTX() { NRFWriteCSN(0); NRFStatus = transferSPI(0xe1); // Send Flush TX command NRFWriteCSN(1); } function NRFFlushRX() { NRFWriteCSN(0); NRFStatus = transferSPI(0xe2); // Send Flush RX command NRFWriteCSN(1); } function NRFSetRXAddress0(AddressLength, Address) { var index; switch (AddressLength) { case 3 : { NRFWriteRegister(3,1); // 3 byte address length break; } case 4 : { NRFWriteRegister(3,2); // 4 byte address length break; } case 5 : { NRFWriteRegister(3,3); // 5 byte address length break; } default: { return -1; // invalid address length } } NRFWriteCSN(0); NRFStatus = transferSPI(0x20+0x0a); // start write to RX_P0_Pipe address for (index = 0; index < AddressLength; index++) { NRFStatus = transferSPI(Address[index]); } NRFWriteCSN(1); } function NRFSetRXAddress1(AddressLength, Address) { var index; switch (AddressLength) { case 3 : { NRFWriteRegister(3,1); // 3 byte address length break; } case 4 : { NRFWriteRegister(3,2); // 4 byte address length break; } case 5 : { NRFWriteRegister(3,3); // 5 byte address length break; } default: { return -1; // invalid address length } } NRFWriteCSN(0); NRFStatus = transferSPI(0x20+0x0b); // start write to RX_P1_Pipe address for (index = 0; index < AddressLength; index++) { NRFStatus = transferSPI(Address[index]); } NRFWriteCSN(1); } function NRFGetRXAddress( MaxAddressLength, Address) { var index; var actual_length; actual_length = NRFReadRegister(3); actual_length = actual_length + 2; if (actual_length > MaxAddressLength) return -1; NRFWriteCSN(0); NRFStatus = transferSPI(0x0a); // start read from RX_P0_Pipe address for (index = 0; index < actual_length; index++) { Address[index] = transferSPI(0xff); } NRFWriteCSN(1); return(0); } function NRFSetTXAddress(AddressLength, Address) { var index; switch (AddressLength) { case 3 : { NRFWriteRegister(3,1); // 3 byte address length break; } case 4 : { NRFWriteRegister(3,2); // 4 byte address length break; } case 5 : { NRFWriteRegister(3,3); // 5 byte address length break; } default: { return -1; // invalid address length } } NRFWriteCSN(0); NRFStatus = transferSPI(0x20+0x10); // start write to TX address for (index = 0; index < AddressLength; index++) { transferSPI(Address[index]); } NRFWriteCSN(1); return(0); } function NRFGetTXAddress(MaxAddressLength, Address) { var index; var actual_length; actual_length = NRFReadRegister(3); actual_length = actual_length + 2; if (actual_length > MaxAddressLength) return -1; NRFWriteCSN(0); NRFStatus = transferSPI(0x10); // start read from TX address for (index = 0; index < actual_length; index++) { Address[index] = transferSPI(0xff); } NRFWriteCSN(1); return(0); } function NRFEnableTXMode() { NRFWriteRegister(0,0x0a); // enable CRC, power up } function NRFEnableRXMode() { NRFWriteRegister(0,0x0b); // enable CRC, power up, RX mode } function NRFWriteData(Length, Data) { var index; if (Length > 32) return -1; // too long NRFWriteCE(0); NRFWriteRegister(0x07,0x70); // clear RX_DR,TX_DS,MAX_RT bits NRFEnableTXMode(); NRFWriteCSN(0); NRFStatus = transferSPI(0xa0); // start write to TX buffer for (index = 0; index < Length; index++) { transferSPI(Data[index]); } NRFWriteCSN(1); NRFWriteCE(1); console.log("Sending.."); NRFEnableRXMode(); } function NRFReadData(MaxLength,Data) { // data is assumeed to be in data pipe 1 var available_bytes; var index; var Length; available_bytes=NRFReadRegister(0x12); // find out how many bytes are available in P1 if (available_bytes == 0) return 0; NRFWriteCSN(0); NRFStatus = transferSPI(0x61); // start read from RX buffer if (available_bytes > MaxLength) Length = MaxLength; else Length = available_bytes; for (index = 0; index < Length; index++) { Data[index]=transferSPI(0xff); } NRFWriteCSN(1); return Length; } function printRegisters() { var regnum; for (regnum = 0;regnum < 0x20; regnum++) { var hexstring= NRFReadRegister(regnum).toString(16); console.log(regnum.toString(16) + " : " + hexstring); } } /* The main body of the program follows. * The NRF is initialized with correct addresses etc and is periodically * polled to see if there is any data available in the RX FIFO * If there is data it is read and a byte is sent back */ var ChannelTraffic = new Buffer(128); function poll() { // check to see if there is any received data var cd=NRFReadRegister(0x09); //console.log(Channel+":"+cd); NRFWriteRegister(0x05,Channel); // select channel NRFWriteCE(1); NRFEnableRXMode(); NRFWriteCE(0); if (cd) ChannelTraffic[Channel] = ChannelTraffic[Channel]+1; Channel++; if (Channel > 127) { Channel = 1; var row=0; var column=0; while(row < 8) { column = 0; while(column < 16) { process.stdout.write(ChannelTraffic[row*16+column]+" "); column++; } console.log(" "); row++; } console.log("-----------------------------------------"); //console.log(ChannelTraffic); } setTimeout(poll,50); } var Channel=0; while(Channel < 128) { ChannelTraffic[Channel]=0; Channel++; } Channel = 0; NRFinit(); NRFSetRXAddress0(5,DESTINATION_ADDRESS); // set auto ack address = destination NRFSetTXAddress(5,DESTINATION_ADDRESS); // set destination address NRFSetRXAddress1(5,SOURCE_ADDRESS); // set source address console.log("Switching to RX mode"); NRFFlushTX(); NRFFlushRX(); NRFEnableRXMode(); NRFWriteRegister(0x05,Channel); // select channel NRFWriteCE(1); printRegisters(); poll();