nRF24l01 + I2C on the ATmega328p - sketch freezes

Hi everyone,

I’m working on a sketch, which has to receive data from I2C (from another ATmega328p) and sent it using nRF24L01 to next chip.

Program freezes when is trying to send data via nRF24. :~

Here is the code:

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

RF24 radio(9,10);
const uint64_t pipe = 0xDEDEDEDAA2LL;

int status_led = 4;
int rx[1];
int x;

void setup()
{
  Serial.begin(9600);
  radio.begin();
  radio.openWritingPipe(pipe);
  Wire.begin(2);
  Wire.onReceive(receiveEvent);
  Serial.println("nRF24 chip");
  
  pinMode(status_led, OUTPUT);
}

void loop() 
{
  radio.write(rx, sizeof(rx));
  delay(1000);
}


void receiveEvent(int howMany)
{
  x = Wire.read();
  Serial.println(x);
  rx[0] = x;
}

When I delete whole function “void receiveEvent”, program runs and nRF24 sends data to another node.

Is someone know what’s wrong? :~

I don't see a call to receiveEvent() ?

Perhaps that means it is called by some interrupt? (like serialEvent())
is that wise?
if there is another way, try it.

...R

Robin2:
I don't see a call to receiveEvent() ?

Perhaps that means it is called by some interrupt? (like serialEvent())
is that wise?
if there is another way, try it.

...R

I total agree with you, also gives half code ... we need both for tx and rx...

Check also the power it is 3.3v ? do you have put a small capacitor 10mf at 3.3v and gnd on both modules ?

Yes, I put capacitor between GND and 3.3V and nRF24 works great when I deleted "void reciveEvent(int HowMany). It isn’t problem with power supply, but with program I think. Here you are all codes which I use.

ethernet program:

#include <EtherCard.h>
#include <Wire.h>
#define STATIC 1 // set to 1 to disable DHCP (adjust myip/gwip values below)

static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
static byte myip[] = { 192,168,1,22 };
static byte gwip[] = { 192,168,1,1 };

byte Ethernet::buffer[700];

const char page[] PROGMEM =
"HTTP/1.0 200 OK\r\n"
"Content-Type: text/html\r\n"
"\r\n"
"<html>"
  "<head><title>"
    "Ardiuno"
  "</title></head>"
  "<body>"
    "<h3>Hello</h3>"
    "<p><em>"
      "Working
"
      "Everything OK"
    "</em></p>"
  "</body>"
"</html>"
;


int lederror = 4;


void setup () 
{
  Wire.begin();
  Serial.begin(9600);
 
  pinMode(lederror, OUTPUT);
  Serial.println("Ethernet chip");

  if (ether.begin(sizeof Ethernet::buffer, mymac) == 0) 
    Serial.println("Ethernet not available");

#if STATIC

  Serial.println( "Setting static IP");
  if (!ether.staticSetup(myip, gwip))
  {
    Serial.println( "Static IP no available");
    Error();     // blink forever to indicate a problem
  }
  
#else

  Serial.println("Setting IP using DHCP");
  if (!ether.dhcpSetup())
  {
    Serial.println("DHCP error");
    Error();     // blink forever to indicate a problem
  }
#endif
  
  ether.printIp("IP:  ", ether.myip);
  ether.printIp("GW:  ", ether.gwip);  
  ether.printIp("DNS: ", ether.dnsip); 

}

void loop () {
  
 
  word len = ether.packetReceive();
  word pos = ether.packetLoop(len);
  
  if(strstr((char *)Ethernet::buffer + pos, "GET /light") != 0) 
    {
      Wire.beginTransmission(2);
      Wire.write(1);
      Wire.endTransmission();
    }
    // show some data to the user
    memcpy_P(ether.tcpOffset(), page, sizeof page);
    ether.httpServerReply(sizeof page - 1);
}

void Error()
{
  while (true)
  {
    digitalWrite(lederror, HIGH);
  }
}

nRF24 writer:

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

RF24 radio(9,10);
const uint64_t pipe = 0xDEDEDEDAA2LL;

int status_led = 4;
int rx[1];
int x;

void setup()
{
  Serial.begin(9600);
  radio.begin();
  radio.openWritingPipe(pipe);
  Wire.begin(2);
  Wire.onReceive(receiveEvent);
  Serial.println("nRF24 chip");
  
  pinMode(status_led, OUTPUT);
}

void loop() 
{
  radio.write(rx, sizeof(rx));
  delay(1000);
}


void receiveEvent(int howMany)
{
  x = Wire.read();
  Serial.println(x);
  rx[0] = x;
}

Client nRF24:

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


int swiatlo = 3;
int lederror = 6;
int rx[1];

RF24 radio(9,10);
const uint64_t pipe = 0xDEDEDEDAA2LL;

void setup()
{
  Serial.begin(9600);

  radio.begin();
  radio.openReadingPipe(1,pipe);
  radio.startListening();
  Serial.println("Client chip (RECEIVE)");
  
  pinMode(swiatlo, OUTPUT);
  pinMode(lederror, OUTPUT);
}
void loop()
{
  if (radio.available())
  {
    Serial.println("radio dostepne");
    digitalWrite(lederror, LOW);
      radio.read(rx, sizeof(rx));
      Serial.print("X = ");
      Serial.print(rx[0]);
      Serial.println();
      if (rx[0] == 1)
      {
        digitalWrite(swiatlo, HIGH);
        Serial.println(" swiatlo ON");
      }
      else
      {
        digitalWrite(swiatlo, LOW);
        Serial.println("swiatlo OFF");
      }
  }
  else
  {
    Serial.println("radio niedostepne");
    digitalWrite(lederror, HIGH);
  }

  delay(1000);
}

You didn’t respond to my question about how receiveEvent() is called.

I did not mean to imply that receiveEvent() should simply be deleted - obviously that leaves your code without some functionality. I meant that you may be able to achieve the same functionality a different way.

…R

I think void reveiveEvent is call here:

void setup()
{
  Serial.begin(9600);
  radio.begin();
  radio.openWritingPipe(pipe);
  Wire.begin(2);
  Wire.onReceive(receiveEvent);  <------- calling void receiveEvent
  Serial.println("nRF24 chip");
  
  pinMode(status_led, OUTPUT);
}

I modeled on the example from here:

http://arduino.cc/en/Tutorial/MasterWriter - “Slave Receiver Code”

I’m a newbie in programming and I ask for your understanding :wink:

I think void reveiveEvent is call here:

No. That is simply registering a handler to be called when the onReceive event happens. The event happens when the wire instance detects data coming in.

When the handler is called, interrupts are disabled. Serial.print() requires that interrupts be enabled, to send data out. If the outgoing buffer is full, Serial.print() blocks, waiting for room to become available. Making room available requires interrupts, which don't happen while your ISR is running, so you have a stalemate, and the ISR will never end. Sounds like exactly what is happening to you.

Thanks for replay :slight_smile: I trying to understand what you mean but still I don't know how your advice can help me to solve this problem. :~ Do you mean that problem is with Serial.println()?

You mean that is problem with Serial.println()?

No. The problem is that you call that function in an ISR. Do NOT do that!

What does it mean ISR? Interrupt Service Routines?

Does it have to do with attachInterrupt ?

The line "Wire.onReceive(receiveEvent);" sets up your function receiveEvent() as an interrupt service routine (ISR). It is called whenever a byte is received (I presume).

As @PaulS says, you can't put print statements into ISRs.
An ISR should be as short as it possibly can be. "rx[0] = Wire.read();" is probably OK. Though you probably need to be able to alter the index of the array if you want to receive several bytes.

If you want to print the data do that elsewhere, outside the ISR.

If there is a function Wire.available() that is equivalent to Serial.available() I would much prefer to use that rather than the interrupt driven Wire.onReceive().

...R

Thanks a lot! :wink: . I'll try to improve my sketch. I'll write if everything is ok or not :wink:

I looked for instructions how to use attachInterrupt but I sill have problem with it. Serial monitor displays “-1”.

Could you tell me what’s wrong?

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

RF24 radio(9,10);
const uint64_t pipe = 0xDEDEDEDAA2LL;

int rx[1];
int pin = 8;

void setup()
{
  Serial.begin(9600);
  radio.begin();
  radio.openWritingPipe(pipe);
  Wire.begin(2);
  attachInterrupt(0, receiveEvent, RISING);
  Serial.println("nRF24 chip");
  
  pinMode(pin, OUTPUT);
}

void loop() 
{
  digitalWrite(pin, HIGH);
  digitalWrite(pin, LOW);
  Serial.println(rx[0]);
  radio.write(rx, sizeof(rx));
  delay(1000);
}


void receiveEvent()
{
  rx[0] = Wire.read();
}

engine1992:
I looked for instructions how to use attachInterrupt

WHY? when we have been trying to tell you to find a solution that doesn't need interrupts.

What's wrong with using if (Wire.available > 0) {  }

...R

I looked for instructions how to use attachInterrupt but I sill have problem with it. Serial monitor displays "-1".

The attachInterrupt() function is how you define what is to be done when an EXTERNAL interrupt happens. It is NOT how you define what happens when the Wire class detects incoming data. What you had before was correct, except for what you were trying to do in the interrupt service routine.

What you have now is a clusterfuck that doesn't stand a snowball's chance in hell of working.

Thanks to everybody for advices! Here’s a sketch which finally working :wink:

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

const uint64_t pipe = 0xE8E8F0F0E1LL; 
RF24 radio(9, 10); 

int rx[1];  

void setup() 
{
  Serial.begin(9600);
  radio.begin();
  radio.openWritingPipe(pipe);
  Wire.begin(2);
}

void loop()   
{
  Wire.onReceive(reciveEvent);
  Serial.println(rx[0]);
  radio.write(rx, sizeof(rx));
}

void reciveEvent (int howMany)
{
  while (Wire.available())
  {
    rx[0] = Wire.read();
  }
}