NRF24L01 example code with Arduino Uno and OpenCM

Hi everyone, I am working with NRF24 connected with Arduino Uno and OPenCM9.04 board as transmitter and receiver respectively or vice versa, using Arduino IDE to upload the code. I had used the same example codes (attached below) on two Arduino Uno and it worked fine. However, now problem is after uploading the codes on OpenCM and Arduino Uno when I open the serial monitor I am not receiving or I can't send any data from OpenCM. The code and hardware setup can be seen below;

Hardware Setup:
Arduino Uno : NRF24
5v --> VCC
GND --> GND
D8 --> CE
D10 --> CSN
D11 --> MOSI
D12 --> MISO
D13 --> SCK

OpenCM904 : NRF24
5v --> VCC
GND --> GND
D16 --> CE
D17 --> CSN
A7 --> MOSI
A6 --> MISO
A1 --> SCK


Transmitter Code:

/*
* Arduino Wireless Communication Tutorial
*     Example 1 - Transmitter Code
*                
* by Dejan Nedelkovski, www.HowToMechatronics.com
* 
* Library: TMRh20/RF24, https://github.com/tmrh20/RF24/
*/
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

RF24 radio(8, 10);  // CE, CSN, SCK->13, MOSI->11, MISO->12 For arduino UNO  

const byte address[6] = "00001";
int time1;

void setup() {

  Serial.begin(115200);
  radio.begin();
  radio.openWritingPipe(address);
  radio.setPALevel(RF24_PA_MIN);
  radio.stopListening();
  Serial.println ("Setup Done");
}
void loop() {
  time1=millis();
  radio.write(&time1, 32);
  Serial.println(time1);
  delay(1);
}

Receiver Code:

/*
* Arduino Wireless Communication Tutorial
*       Example 1 - Receiver Code
*                
* by Dejan Nedelkovski, www.HowToMechatronics.com
* 
* Library: TMRh20/RF24, https://github.com/tmrh20/RF24/
*/
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

RF24 radio(16, 17);   //CE, CSN (16,17), SCK->A1, MOSI->A7, MISO->A6 FOr OpenCM 
                  
const byte address[6] = "00001";
int time1;

void setup() {
  Serial.begin(115200);
  radio.begin();
  radio.openReadingPipe(0, address);
  //radio.setDataRate(RF24_250KBPS);
  radio.setPALevel(RF24_PA_MIN);
  radio.startListening();
  Serial.println("Setup Done");
}
void loop() {
  if (radio.available()) {
    Serial.print("Received: ");
    radio.read(&time1, 10);
    Serial.println(time1);
    Serial.println("loop running");
  }
 else {
  Serial.println("Receiving Failed");
}
}

Serial monitor (Receiver):

Receiving Failed
Receiving Failed
Receiving Failed

Serial monitor (Transmitter):

Setup Done
10
43
75
108

The problem must should be with the OpenCM board as the code can also be uploaded but it isn't receiving any data from transmitter. I also don't know whether we can connect NRF24 with OpenCM or not, also may be the way I have wired the NRF24 with OpenCM904 is not correct.
It would be great if any one can help and thanks.

Very strange, I doubt that is from the example code, and it can lead to unexpected behavior.

While reading from not owned memory does not hurt on most Arduinos,

int time1;

  time1=millis();
  radio.write(&time1, 32);

that code is still strange too.

BTW, on an UNO, ints can not hold the value returned by millis().

Your "receiving failed" is to be expected, most of the time there will be no packet.
It's not a good idea to print under that circumstance.
Print when you had no reception in the last second, or whatever suits you.

1 Like

After a quick glance over the documentation, it seems the NRF should work without problems.

If you are unsure about the connections, run a connection test program,
that only displays the register dump of the initialized sysytem .

I was looking up some documentation here:
https://emanual.robotis.com/docs/en/parts/controller/opencm904/

which says
OpenCM9.04 is a microcontroller board based on 32bit ARM Cortex-M3

Did you adjust the arduino-IDE to this microcontroller?
best regards Stefan

No, it is not from example code, I just tried it. Actually, this code works on UNO however it doesn't on OpenCM may be reason could be it is reading from owned memory (as you mentioned).

Yes, I updated the code following these recommendations and now it is working on OpenCM.
many thanks.

Yes the connections were right, and NRF was not working because of the coding mistakes.
BTW, currently I don't how to run a connection test program! I will definitely learn it and will try.

I couldn't understand how we can adjust the Arduino IDE to this microcontroller... Actually I am not getting any problem during uploading the code and running it. Thanks

So I want to ask for more details:

Are you able to upload code into the OpenCM9.04?

Can you post a smartphone-picture of the OpenCM9.04 you are using?

Can you post a link to the datasheet of the OpenCM9.04 you are using?
best regards Stefan

You should post the now 'working'* versions of the sketches,
maybe we can spot some problems, or give you hints for improvement.

*you told us the starting sketch would work on UNOs, which was just luck.

Yes, I can upload the code.

I also follow the same link which you sent before.
[OpenCM 9.04]
Thanks

As the OPenCM9.04 is a board that has a 32bit ARM Cortex-M3 microcontroller this means you

do

adjust the Arduino-IDE to the OPenCM9.04-Board.

Yes by luck that code worked on UNO but not on OpenCM.

Yes here is the code
Transmitter:

/*
        DIY Arduino based RC Transmitter
  by Dejan Nedelkovski, www.HowToMechatronics.com
  Library: TMRh20/RF24, https://github.com/tmrh20/RF24/
*/

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

//===============Button======================
int buttonPin1=7;
int buttonPin2=4;
int buttonVal1;
int buttonVal2;
int DXLpos=0;
int dt=10;
unsigned long currentT, previousT=0;
//====================================================

RF24 radio(8, 10);   // nRF24L01 (CE, CSN) for UNO
//RF24 radio(16, 17);   // nRF24L01 (CE, CSN)for OpenCM
const byte address[6] = "00001"; // Address

unsigned long lastReceiveTime = 0;
unsigned long currentTime = 0;

// Max size of this struct is 32 bytes - NRF24L01 buffer limit
struct Data_Package {
  byte DXPos;
};

Data_Package data; //Create a variable with the above structure
  
void setup() {
  Serial.begin(115200);

    //=====================================================
  pinMode(buttonPin1,INPUT);
  pinMode(buttonPin2,INPUT);
  //=========================================================
  
 // Define the radio communication
  radio.begin();
  radio.openWritingPipe(address);
  radio.setAutoAck(false);
  radio.setDataRate(RF24_250KBPS);
  radio.setPALevel(RF24_PA_LOW);

  resetData();
}
void loop() {

buttonVal1=digitalRead(buttonPin1);
buttonVal2=digitalRead(buttonPin2);
 
if (buttonVal1==0){
  DXLpos=DXLpos+1;
}
if (buttonVal2==0){
  DXLpos=DXLpos-1;
}
if (DXLpos>250){
  DXLpos=250;
  
}
if (DXLpos<0){
  DXLpos=0;
}
//====================================================================

  data.DXPos=DXLpos;
  radio.stopListening();
  // Send the whole data from the structure to the receiver
  radio.write(&data, sizeof(Data_Package));

Serial.print("B1 = ");
Serial.print(buttonVal1);
Serial.print(", ");
Serial.print("B2 = ");
Serial.print(buttonVal2);
Serial.print(", ");
Serial.print("DXL = ");
Serial.print(DXLpos);
Serial.print(", ");
Serial.println(data.DXPos);
}

void resetData() {
  // Reset the values when there is no radio connection - Set initial default values
 Serial.println("No data available");   
}

Receiver:

/*
    DIY Arduino based RC Transmitter Project
              == Receiver Code ==

  by Dejan Nedelkovski, www.HowToMechatronics.com
  Library: TMRh20/RF24, https://github.com/tmrh20/RF24/
*/
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

RF24 radio(16, 17);   // nRF24L01 (CE, CSN) // CE, CSN //SCK->13, MOSI->11, MISO->12 FOr UNO  
const byte address[6] = "00001";

unsigned long lastReceiveTime = 0;
unsigned long currentTime = 0;

// Max size of this struct is 32 bytes - NRF24L01 buffer limit
struct Data_Package {
 byte DXPos;
};

Data_Package data; //Create a variable with the above structure

void setup() {
   Serial.begin(115200);
  radio.begin();
  radio.openReadingPipe(1, address);
  radio.setAutoAck(false);
  radio.setDataRate(RF24_250KBPS);
  radio.setPALevel(RF24_PA_LOW);
  radio.startListening(); //  Set the module as receiver
  resetData();
}
void loop() {
  // Check whether there is data to be received
  if (radio.available()) {
    radio.read(&data, sizeof(Data_Package)); // Read the whole data and store it into the 'data' structure
    lastReceiveTime = millis(); // At this moment we have received the data
  }
  
  // Check whether we keep receving data, or we have a connection between the two modules
  currentTime = millis();
  if ( currentTime - lastReceiveTime > 10000 ) { // If current time is more then (10000)1 second since we have recived the last data, that means we have lost connection
    resetData(); // If connection is lost, reset the data. It prevents unwanted behavior, for example if a drone has a throttle up and we lose connection, it can keep flying unless we reset the values
  }
  Serial.print("DXL: ");
  Serial.println(data.DXPos);   
}

void resetData() {
  // Reset the values when there is no radio connection - Set initial default values
 Serial.println("No data available");   
}

Is it about selecting the OpenCM board and right port in Arduino IDE... (I already adjusted it and code is uploading). Thanks again

This routine and its call are superfluous and print a misleading message in the transmitter.

The newest library needs one of those calls for the transmitter, move it to setup.

If you want to add more members to the struct, remember to use

struct Data_Package {
  byte DXPos;
  byte DYPos;
} __attribute__((packed, aligned(1)));

to pack the structures equally to byte bounderies,
otherwise the 32 bit struct would probably have a different layout.

In the receiver loop you print this information on every round of loop,
that is much too often and will block sooner or later.

If you enable dynamic payloads in both sketches, the transmissions are faster.
Now you are sending 32 byte data with only one byte used,
while you could send just that one byte (in both cases plus the overhead of a packet,
which is constant regardless of the data content.

enableDynamicPayloads()

1 Like

This could be solved by code like this
defining two macros

#define dbg(myFixedText, variableName) \
  Serial.print( F(#myFixedText " "  #variableName"=") ); \
  Serial.println(variableName);
// usage: dbg("1:my fixed text",myVariable);
// myVariable can be any variable or expression that is defined in scope

#define dbgi(myFixedText, variableName,timeInterval) \
  do { \
    static unsigned long intervalStartTime; \
    if ( millis() - intervalStartTime >= timeInterval ){ \
      intervalStartTime = millis(); \
      Serial.print( F(#myFixedText " "  #variableName"=") ); \
      Serial.println(variableName); \
    } \
  } while (false);
// usage: dbgi("2:my fixed text",myVar,myInterval);
// myVar can be any variable or expression that is defined in scope
// myInterval is the time-interval which must pass by before the next
// print is executed

and then use the macro very similar to any other function-call
instead of

  Serial.print("DXL: ");
  Serial.println(data.DXPos);   

code

dbgi("DXL:",data.DXPos,1000);

which does print the value DXPos only once every second (1000 milliseconds)

best regards Stefan

2 Likes

Yes, I have deleted this.

I modified it.

Nice information, before I used the same struc code for more variables but now I will update it with

[quote="Whandall, post:14, topic:897390"]

I modified it with millis function and now data will be printing after every second.

I will try this too. And again many thanks for comments.

Thanks for improving the code, Should I just use millis function

instead of the whole code if there is no any difference...

dbgi has some more code that is genious! It is a brilliant idea proposed by user
Coding_Badly So his username is self-ironic

a do - while -loop with a fixed condition "false"

At first view this seems to be nonsense a do-while-loop where the condition always evaluates to "false" means
run down the code only once

so why not leave away the do-while-loop???

The purpose of adding the while-loop is it makes the variable intervalStartTime
local to the while-loop

This has the effect that with mutliples calls of macro dbgi
the always the same named variable intervalStartTime are each local and don't disturb each other.

This means the macro dbgi can be called at thousands different places in the code where each call has its own set of variables.

1 Like