nRF24L01 emulation

I have a wireless flash trigger that i am trying to trigger using arduino the model is rfn4 it has a pic16f677 2 buttons and a 4 bit dip switch and communicate through spi to a nRF24L01.

I have a few nRF24L01 on the way and would like to k ow how i should proceed to emulate the trigger.

The fcc page is here https://fccid.io/WU2SMRSRFN4

For one nRF24 to communicate with another it is necessary to know the channel (frequency) and the address of the device you want to talk to. There are 2555 possible addresses so you will be very lucky if you can guess it.

I think the link you posted is just about general approval for nRF24 devices and I doubt if it has info relevant to the specific product you want to communicate with - but I confess to being too lazy to read it all.

The source code for PIC MCU will have the details you need if you can get access to it.

…R
Simple nRF24L01+ Tutorial

Robin2:
There are 2555 possible addresses so you will be very lucky if you can guess it.

If the device uses fixed address, you may try to intercept it. I am not sure if it is possible with nRF24L01, but possibly using some tricks it may reduce possible addresses. I.e. configure the nRF as PRX without ShockBurst and CRC control, only 3 byte address reduces it to 256^3. Or set fixed payload length as maximum - if you are lucky you may intercept begining of ACK packet - which includes address.
Ofc much easier is using a logic analyzer to intercept SPI communication between the PIC and nRF and read what address it sets (or if default is used).

Smajdalf: Ofc much easier is using a logic analyzer to intercept SPI communication between the PIC and nRF and read what address it sets (or if default is used).

That could be a solution. But I suspect it would still require a lot of patience.

IMHO it would probably be simpler just to replace the PIC based system altogether.

...R

Smajdalf: I.e. configure the nRF as PRX without ShockBurst and CRC control, only 3 byte address reduces it to 256^3. Or set fixed payload length as maximum

You can even use 2 byte addresses* and the first byte of that can be made one of the two possible preambles. ;) You should set the payload to maximum and you have to check the crc yourself, likewise the one bit shift neccessary due to the 9 bit control field.

  • a small change to the library may be necessary to pass the 'illegal' 0 value to the chip.

Robin2: That could be a solution. But I suspect it would still require a lot of patience.

Why? The PRX must configure the nRF after reset. If OP has appropriate skill and physical access to one side of the communication it should be easy task to connect an analyzer to the SPI lines, trigger a (power on?) reset and collect data from the first few seconds. Following nRF Datasheet should be easy to find which registers and how are written.

Maybe hacking into PTX would be even better - you can also read what data it sends and what it reads from ACK (if anything). If it does not use some advanced protocol OP can even use a brain-dead approach: copy the SPI commands and send the same sequence to another nRF without actually knowing what and why it does.

Smajdalf: Following nRF Datasheet should be easy to find which registers and how are written.

I admire your greater expertise.

It would require more of my patience than I would be willing to contribute :)

...R

thank you everyone for your input its getting me more fired up to solve this i just ordered a DSLogic Logic Analyzer Module USB Based 400M Sampling Rate 16 Ch f/Debugging US and will try to capture the signals and hopefully make since of them

ok i got my logic analyse and i may need help understanding the output i hooked it up but i am unable to figure out what i am seeing

just a update i managed to pull some data out. now i need to figure out how to code this is arduino

CHIP:nRF24L01+ SWITCH SET TO: 0000 MODE: FOCUS

Cmd W_REGISTER: Config = "0F" Cmd W_REGISTER: SETUP_AW="01" Cmd W_REGISTER: TX_ADDR = "C7B6A5" Cmd W_REGISTER: RX_ADDR_P0 = "C7B6A5" Cmd FLUSH_TX Cmd FLUSH_RX Cmd W_REGISTER: EN_AA = "00" Cmd W_REGISTER: EN_RXADDR = "01" Cmd W_REGISTER: RF_CH = "59"\ Cmd W_REGISTER: RX_PW_P0 = "01" Cmd W_REGISTER: RF_SETUP = "26" Cmd W_TX_PAYLOAD TX_payload = "\xA0" Cmd W_REGISTER: Config = "0F" Cmd W_REGISTER: STATUS = "70" Cmd FLUSH_RX

d1ed76a372423061ee3b5bf1f4c28b2f09a674db.png

23 01
0E 00

W_REGISTER AW = 1 (address size = 3)

10 00 00 00
0E A5 B6 C7

R_REGISTER TX_ADDR = A5 B6 C7 

0A 00 00 00
0E A5 B6 C7

R_REGISTER RX_ADDR_P0 = A5 B6 C7

E1 00
0E 00

FLUSH_TX

E2 00
0E 00

FLUSH_RX

22 01
0E 00

W_REGISTER EN_RXADDR = 01

E3 00
0E 00

REUSE_TX_PL

20 0E
0E 00

W_REGISTER CONFIG = 0E

A0 5A
0E 00

W_TX_PAYLOAD = 5A

E3 00
0E 00

REUSE_TX_PL

27 F0
0E 00

W_REGISTER STATUS = F0 (writing 1 to reserved bit 7)

23 01
0E 00

W_REGISTER AW = 1 (address size = 3)

30 A5 B6
0E 00 00

W_REGISTER TX_ADDR = A5 B6 (only fragment of command)

So it looks like packet data is ‘5A’, used address width is 3, used address is ‘A5 B6 C7’

From you overlapping post:

Speed 250kbps, MAX_POWER, channel 59, no autoack.

i seem to be having a problem with my esp wemo d1 mini crashing as soon as it runs radio.openWritingPipe(slaveAddress);

Soft WDT reset

stack>>>

ctx: cont
sp: 3ffffd60 end: 3fffffc0 offset: 01b0
3fffff10: 401001a4 3ffee380 3ffee360 401001cd
3fffff20: 00000000 3ffee360 3ffee380 40202acc
3fffff30: 3fffdad0 00000000 3ffee360 40202b20
3fffff40: 3fffdad0 000000ff 3ffee360 40202cda
3fffff50: 3fffdad0 00000030 3ffee360 40202d24
3fffff60: 00000000 00000030 3ffee360 40202dde
3fffff70: 00090882 3ffe84d1 3ffee358 40202e23
3fffff80: 3fffdad0 3ffe8618 3ffee360 40202585
3fffff90: 3fffdad0 00000000 3ffee358 402025fc
3fffffa0: 3fffdad0 00000000 3ffee3c8 402036a4
3fffffb0: feefeffe feefeffe 3ffe84fc 40100a0d
<<<stack<<<
⸮⸮⸮⸮⸮⸮d*⸮

code so far

// SimpleTx - the master or the transmitter

//NRF               Wemo d1 mini
//CSN ---------------- D8
//MOSI --------------- D7
//MISO --------------- D6
//SCK ---------------- D5
//CE ----------------- D0

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

#define CE_PIN D4 
#define CSN_PIN D8

const byte slaveAddress[3] = {'A5','B6','C7'};
RF24 radio(CE_PIN, CSN_PIN); // Create a Radio

char dataToSend[3] = "\xA0";
char txNum = '0';

unsigned long currentMillis;
unsigned long prevMillis;
unsigned long txIntervalMillis = 2000; // send once per second

void setup() {

   Serial.begin(9600);

   Serial.println("SimpleTx Starting");
   
   Serial.println("Radio Begin");
   radio.begin();
   Serial.println("Set CH to 59");   
   radio.setChannel(59);
   Serial.println("Setting address width");   
   radio.setAddressWidth(3);
   Serial.println("Ack = false");
   radio.setAutoAck(false);
   Serial.println("PALevel=max");
   radio.setPALevel(RF24_PA_MIN); 
   Serial.println("datarate= 250KBPS");
   radio.setDataRate( RF24_250KBPS );
   Serial.println("Setting retrys");
   radio.setRetries(3,5); // delay, count
   Serial.println("OpenWritingPipe");
   radio.openWritingPipe(slaveAddress);

}

//====================

void loop() {
   currentMillis = millis();
   if (currentMillis - prevMillis >= txIntervalMillis) {
       send();
       prevMillis = millis();
   }
}

//====================

void send() {
   bool rslt;
   rslt = radio.write( &dataToSend, sizeof(dataToSend) );
       // Always use sizeof() as it gives the size as the number of bytes.
       // For example if dataToSend was an int sizeof() would correctly return 2

   Serial.print("Data Sent ");
   Serial.print(dataToSend);
   if (rslt) {
       Serial.println("  Acknowledge received");
       updateMessage();
   }
   else {
       Serial.println("  Tx failed");
   }
}

//================

void updateMessage() {
       // so you can see that new data is being sent
   txNum += 1;
   if (txNum > '9') {
       txNum = '0';
   }
   dataToSend[8] = txNum;
}

Some errors I see.

char dataToSend[3] = "\xA0";

The data I have seen was one byte long and had the value 0x5A 'Z', where do you get the three bytes and the A0 00 00 from?

const byte slaveAddress[3] = {'A5','B6','C7'};

Strange way to define hex bytes.

   radio.setChannel(59);

The value should to be 0x59 I think.

   Serial.println("PALevel=max");
   radio.setPALevel(RF24_PA_MIN);

A Lie.

   radio.setAutoAck(false);
...
       Serial.println("  Acknowledge received");

Another lie.

   dataToSend[8] = txNum;

Writing out of bounds.

Start writing programs, don't copy and paste. ;)

RF24 radio(CE_PIN, CSN_PIN); // Create a Radio

Superfluous comments are nearly as bad as wrong ones IMHO.

i appreciate all the help i am determined to learn this.
i got the \xA0 from http://i65.tinypic.com/2hx0m11.png
the payload for focusing was “\xA0” and shooting a photo was “Z”
as for the high low power i just forgot to change the comment as i changed it to low to see if it was a power problem and was going to change it back as it crashed either way.
the CE was that originally then i changed it and forgot to update the comment
it didn’t even occur to me to use 0x for hex i don’t normally use hex too much, i am still learning
i was actually meaning to take the comments out of the setup as i was just trying to see where it was crashing.

i updated the code to reflect those changes and it still crashes

// SimpleTx - the master or the transmitter

//NRF               Wemo d1 mini
//CSN ---------------- D8
//MOSI --------------- D7
//MISO --------------- D6
//SCK ---------------- D5
//CE ----------------- D0

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

#define CE_PIN D0
#define CSN_PIN D8

const byte slaveAddress[3] = {0xA5, 0xB6, 0xC7};
RF24 radio(CE_PIN, CSN_PIN); // Create a Radio

char dataToSend[] = "Z";
//focus: \xA0
//shoot: Z


unsigned long currentMillis;
unsigned long prevMillis;
unsigned long txIntervalMillis = 2000; // send once per second

void  () {

  Serial.begin(9600);
  Serial.println("SimpleTx Starting");
  radio.begin();
  radio.setChannel(0x59);
  radio.setAddressWidth(3);
  radio.setAutoAck(false);
  radio.setPALevel(RF24_PA_MAX);
  radio.setDataRate( RF24_250KBPS );
  radio.setRetries(3, 5); // delay, count
  radio.openWritingPipe(slaveAddress);

}

//====================

void loop() {
  currentMillis = millis();
  if (currentMillis - prevMillis >= txIntervalMillis) {
    send();
    prevMillis = millis();
  }
}

void send() {
radio.write( &dataToSend, sizeof(dataToSend) );
  // Always use sizeof() as it gives the size as the number of bytes.
  // For example if dataToSend was an int sizeof() would correctly return 2
  Serial.print("Data Sent ");
  Serial.println(dataToSend);
}

Michael040990: i got the \xA0 from http://i65.tinypic.com/2hx0m11.png the payload for focusing was "\xA0" and shooting a photo was "Z"

I saw the 0xA0, but both commands have a single byte, why do you want to send two?

Did you verify the basic operation of the NRF24L01 with printDetails?

// SimpleTx - the master or the transmitter

  // Always use sizeof() as it gives the size as the number of bytes.
  // For example if dataToSend was an int sizeof() would correctly return 2

Why have you still that crappy copied stuff in there?

unsigned long txIntervalMillis = 2000; // send once per second

And why the wrong comment?

 Serial.println(dataToSend);

This will not work for a single byte if defined as dataToSend[1].

You know that there is a tool that can decode the stacktrace?

https://github.com/me-no-dev/EspExceptionDecoder

i switched to a arduino uno until i can figure this out it is connected and reading the nrf varied by isChipConnected and removed unnecessary comments and code.
i may hook it back up to the logic analyser to see if its sending the right information as its still not triggering the flash.

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

#define CE_PIN 9
#define CSN_PIN 10

const uint64_t slaveAddress = {0xC7B6A5};
RF24 radio(CE_PIN, CSN_PIN);

byte dataToSend = 0x5A;
void setup() {

  Serial.begin(9600);
  radio.begin();
  radio.setAddressWidth(3);
  Serial.println("checking if chip connected");
  bool check = radio.isChipConnected();
  Serial.println((String)"check:"+check);
  radio.printDetails();
  radio.setChannel(59);
  radio.setAutoAck(false);
  radio.setPALevel(RF24_PA_MAX);
  radio.setDataRate(RF24_250KBPS);
  radio.setRetries(3, 5); // delay, count
  radio.printDetails();
  radio.openWritingPipe(slaveAddress);

}

void loop() {
if (radio.write( &dataToSend, sizeof(dataToSend) )){
  Serial.println("Data Sent ");
   }else {
   Serial.println("Failed to send data");
   }
  delay(2000);
}

i have a full list of the decoded nrf commands from the logic analyser here

ID,Time[s],nRF24L01(+): Commands
0,7.65e-05,Cmd W_REGISTER: SETUP_AW = "01"
1,0.000241,Cmd R_REGISTER "TX_ADDR"
2,0.0005665,Cmd R_REGISTER "RX_ADDR_P0"
3,0.000891,Cmd FLUSH_TX
4,0.001056,Cmd FLUSH_RX
5,0.001221,Cmd W_REGISTER: EN_RXADDR = "01"
6,0.001386,Cmd REUSE_TX_PL
7,0.0015505,Cmd W_REGISTER: CONFIG = "0E"
8,0.001715,Cmd W_TX_PAYLOAD
9,0.001794,TX payload = "Z"
10,0.0018785,Cmd REUSE_TX_PL
11,0.002043,Cmd W_REGISTER: STATUS = "F0"
12,0.002261,Cmd W_REGISTER: SETUP_AW = "01"
13,0.002426,Cmd W_REGISTER: TX_ADDR = "	"
14,0.002744,Cmd R_REGISTER "TX_ADDR"
15,0.003069,Cmd W_REGISTER: RX_ADDR_P0 = "C7B6A5"
16,0.0033865,Cmd R_REGISTER "RX_ADDR_P0"
17,0.003711,Cmd FLUSH_TX
18,0.003876,Cmd FLUSH_RX
19,0.004041,Cmd W_REGISTER: EN_AA = "00"
20,0.004207,Cmd W_REGISTER: EN_RXADDR = "01"
21,0.004372,Cmd W_REGISTER: RF_CH = "59"
22,0.0045355,Cmd W_REGISTER: RX_PW_P0 = "10"
23,0.0046995,Cmd REUSE_TX_PL
24,0.004864,Cmd W_REGISTER: RF_SETUP = "26"
25,0.005028,Cmd W_REGISTER: CONFIG = "0E"
26,0.005192,Cmd W_TX_PAYLOAD
27,0.005271,TX payload = "\xA0"
28,0.005357,Cmd REUSE_TX_PL
29,0.0055215,Cmd W_REGISTER: STATUS = "F0"
30,0.0056915,Cmd W_REGISTER: SETUP_AW = "01"
31,0.005856,Cmd R_REGISTER "TX_ADDR"
32,0.0061815,Cmd R_REGISTER "RX_ADDR_P0"
33,0.006506,Cmd FLUSH_TX
34,0.006671,Cmd FLUSH_RX
35,0.006836,Cmd W_REGISTER: EN_RXADDR = "01"
36,0.007001,Cmd REUSE_TX_PL
37,0.0071655,Cmd W_REGISTER: CONFIG = "0E"
38,0.0073295,Cmd W_TX_PAYLOAD
39,0.007409,TX payload = "Z"
40,0.0074935,Cmd REUSE_TX_PL
41,0.007658,Cmd W_REGISTER: STATUS = "F0"
42,0.007876,Cmd W_REGISTER: SETUP_AW = "01"
43,0.008041,Cmd W_REGISTER: TX_ADDR = "C7B6A5"
44,0.008359,Cmd R_REGISTER "TX_ADDR"
45,0.008684,Cmd W_REGISTER: RX_ADDR_P0 = "C7B6A5"
46,0.0090015,Cmd R_REGISTER "RX_ADDR_P0"
47,0.009326,Cmd FLUSH_TX
48,0.009491,Cmd FLUSH_RX
49,0.009656,Cmd W_REGISTER: EN_AA = "00"
50,0.009822,Cmd W_REGISTER: EN_RXADDR = "01"
51,0.009987,Cmd W_REGISTER: RF_CH = "59"
52,0.0101505,Cmd W_REGISTER: RX_PW_P0 = "10"
53,0.0103145,Cmd REUSE_TX_PL
54,0.010479,Cmd W_REGISTER: RF_SETUP = "26"
55,0.010643,Cmd W_REGISTER: CONFIG = "0E"
56,0.010807,Cmd W_TX_PAYLOAD
57,0.010886,TX payload = "\xA0"
58,0.010972,Cmd REUSE_TX_PL
59,0.0111365,Cmd W_REGISTER: STATUS = "F0"
60,0.0113065,Cmd W_REGISTER: SETUP_AW = "01"
61,0.011471,Cmd R_REGISTER "TX_ADDR"
62,0.0117965,Cmd R_REGISTER "RX_ADDR_P0"
63,0.012121,Cmd FLUSH_TX
64,0.012286,Cmd FLUSH_RX
65,0.012451,Cmd W_REGISTER: EN_RXADDR = "01"
66,0.012616,Cmd REUSE_TX_PL
67,0.0127805,Cmd W_REGISTER: CONFIG = "0E"
68,0.012945,Cmd W_TX_PAYLOAD
69,0.013024,TX payload = "Z"
70,0.0131085,Cmd REUSE_TX_PL
71,0.0132735,Cmd W_REGISTER: STATUS = "F0"
72,0.013491,Cmd W_REGISTER: SETUP_AW = "01"
73,0.013656,Cmd W_REGISTER: TX_ADDR = "C7B6A5"
74,0.013974,Cmd R_REGISTER "TX_ADDR"
75,0.0142995,Cmd W_REGISTER: RX_ADDR_P0 = "C7B6A5"
76,0.014617,Cmd R_REGISTER "RX_ADDR_P0"
77,0.014941,Cmd FLUSH_TX
78,0.015106,Cmd FLUSH_RX
79,0.015271,Cmd W_REGISTER: EN_AA = "00"
80,0.015437,Cmd W_REGISTER: EN_RXADDR = "01"
81,0.015602,Cmd W_REGISTER: RF_CH = "59"
82,0.0157655,Cmd W_REGISTER: RX_PW_P0 = "10"
83,0.0159295,Cmd REUSE_TX_PL
84,0.0160945,Cmd W_REGISTER: RF_SETUP = "26"
85,0.016258,Cmd W_REGISTER: CONFIG = "0E"
86,0.0164225,Cmd W_TX_PAYLOAD
87,0.016501,TX payload = "\xA0"
88,0.016587,Cmd REUSE_TX_PL
89,0.016752,Cmd W_REGISTER: STATUS = "F0"
90,0.0169175,Cmd W_REGISTER: CONFIG = "0F"
91,0.017082,Cmd W_REGISTER: SETUP_AW = "01"
92,0.0172465,Cmd W_REGISTER: TX_ADDR = "C7B6A5"
93,0.0175645,Cmd W_REGISTER: RX_ADDR_P0 = "C7B6A5"
94,0.0178815,Cmd FLUSH_TX
95,0.018046,Cmd FLUSH_RX
96,0.0182115,Cmd W_REGISTER: EN_AA = "00"
97,0.018377,Cmd W_REGISTER: EN_RXADDR = "01"
98,0.0185425,Cmd W_REGISTER: RF_CH = "59"
99,0.0187055,Cmd W_REGISTER: RX_PW_P0 = "01"
100,0.0188705,Cmd W_REGISTER: RF_SETUP = "26"
101,0.0190335,Cmd W_TX_PAYLOAD
102,0.019112,TX payload = "\xA0"
103,0.019199,Cmd W_REGISTER: CONFIG = "0F"
104,0.019363,Cmd W_REGISTER: STATUS = "70"
105,0.0195215,Cmd FLUSH_RX
106,0.186499,Cmd W_REGISTER: SETUP_AW = "01"
107,0.186664,Cmd W_REGISTER: TX_ADDR = "C7B6A5"
108,0.186982,Cmd R_REGISTER "TX_ADDR"
109,0.187308,Cmd W_REGISTER: RX_ADDR_P0 = "C7B6A5"
110,0.187625,Cmd R_REGISTER "RX_ADDR_P0"
111,0.187949,Cmd FLUSH_TX
112,0.188114,Cmd FLUSH_RX
113,0.188279,Cmd W_REGISTER: EN_AA = "00"
114,0.188445,Cmd W_REGISTER: EN_RXADDR = "01"
115,0.18861,Cmd W_REGISTER: RF_CH = "59"
116,0.188774,Cmd W_REGISTER: RX_PW_P0 = "10"
117,0.188938,Cmd REUSE_TX_PL
118,0.189103,Cmd W_REGISTER: RF_SETUP = "26"
119,0.189267,Cmd W_REGISTER: CONFIG = "0E"
120,0.189431,Cmd W_TX_PAYLOAD
121,0.189509,TX payload = "\xA0"
122,0.189596,Cmd REUSE_TX_PL
123,0.18976,Cmd W_REGISTER: STATUS = "F0"

And the device you are reading does trigger the flash by the captured sequence? Maybe it is only a "I am still here" message?

Line 24: 22,0.0045355,Cmd W_REGISTER: RX_PW_P0 = "10"
Line 54: 52,0.0101505,Cmd W_REGISTER: RX_PW_P0 = "10"
Line 84: 82,0.0157655,Cmd W_REGISTER: RX_PW_P0 = "10"
Line 101: 99,0.0187055,Cmd W_REGISTER: RX_PW_P0 = "01"
Line 118: 116,0.188774,Cmd W_REGISTER: RX_PW_P0 = "10"

There is one packet size one, and many sixteen, none in your sketch (which implies thirtytwo). Somehow the sixteen seems strange, given the one byte packets that are written.

On the other hand it's only the receive packet size, which only happens to have influence on the sended packet sizes in the usual libraries. So now you are sending 32 byte packets, filled up with zeros. You could use enableDynamicPayloads() or set the desired packet size.

const uint64_t slaveAddress = {0xC7B6A5};

Why do you want to waste 5 bytes now?

  Serial.println((String)"check:"+check);

Introducing String to concatenate output is not worth it, just print the parts one after another. While it looks like more code it actually is a lot smaller (code and RAM).

  Serial.print(F("check: "));
  Serial.println(check ? F("ok") : F("fail"));