Go Down

Topic: RF24 Library: Driver for nRF24L01(+) 2.4GHz Wireless Transceiver (Read 236221 times) previous topic - next topic

RobDrizzle

great information.

I do have both devices patched through a breadboard and was wondering if the signal was being distorted because of it. My next diagnostic step was to solder connect everything to eliminate that, so it's nice to know that I won't waste my time.

The speed comment is also a really good idea. My only concern is that I know very little about SPI communication so it will have to take some digging to find out where to look and how to change it.

Thank you.

crofter

@sej7278 .. The steps I went through to get RF24 and RF24Network working on an attiny84 were:

Install the libraries rf24, rf24network and spi  from https://github.com/jscrane
Write the sketch to use the libraries taking care to keep the number of variables small and use the minimum debugging statements possible. I found I was limited by ram rather than program space so I used avr-size and avr-objdump a lot to look at the compiled code to see where all the space was being used. My testing sketch is below, it includes a ram checking routine but calling it too often wastes space. It also includes commented debug statements but if you uncomment one you need to comment others to keep ram usage down. 
Code: [Select]

#include <dht11.h>
#include <RF24Network.h>
#include <RF24.h>
#include <SPI.h>

#include <TinyDebugSerial.h>
TinyDebugSerial mySerial = TinyDebugSerial(); // PB0 on attiny84

dht11 DHT11;

#define DHT11PIN 9
#define PIRPIN 8

uint8_t pirstate = 0;
uint8_t val = 0;

RF24 radio(7,3);
// Network uses that radio
RF24Network network(radio);

RF24NetworkHeader * myheader;

// Address of our node
const uint16_t this_node = 2;

// Address of the other node
const uint16_t other_node = 0;

unsigned int counter = 0;

unsigned long temp_timeout;
unsigned long pir_timeout;

unsigned long temp_delay = 1000;
unsigned long pir_delay = 500;

// Structure of our temp payload
struct payload_th
{
  uint16_t counter;
  int8_t temp;
  int8_t humidity;
};
// Structure of our pir payload
struct payload_pir
{
  uint16_t counter;
  uint8_t pir_state;
};

bool PIR_state;

int freeRam () {
  extern int __heap_start, *__brkval;
  int v;
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}

void setup(void)
{
  uint8_t rf_ch;
 
  mySerial.begin(9600);
  mySerial.println("Start");
 
//  mySerial.print("start ram ");
//  mySerial.println(freeRam());
 
  pinMode(PIRPIN, INPUT);
 
  SPI.begin();
  radio.begin();
  network.begin(/*channel*/ 90, /*node address*/ this_node);
/* 
  rf_ch = radio.getChannel();
  mySerial.print("RF_CH :0x");
  mySerial.println(rf_ch,HEX); 
*/

temp_timeout = millis();
pir_timeout = millis();

}

void loop(void)
{
// Pump the network regularly
  network.update();

// This method used to avoid millis() rollover issues

  if ((unsigned long) millis() - temp_timeout >= temp_delay) {
    checkTemp();
    temp_timeout = temp_timeout + temp_delay;
  }
  if ((unsigned long) millis() - pir_timeout >= pir_delay) {
    checkPIR();
    pir_timeout = pir_timeout + pir_delay;
  }
}

void sendPIR()
{

  counter++;

  payload_pir payload = { counter, pirstate };

  mySerial.print("Sending PIR...");

  RF24NetworkHeader header(/*to node*/ other_node,/*message type*/ '3');
       
  bool ok = network.write(header,&payload,sizeof(payload));
  if (ok)
     mySerial.println("ok.");
  else
     mySerial.println("failed.");

}

void sendTemp()
{

  counter++;

  payload_th payload = { counter, DHT11.temperature, DHT11.humidity };

  mySerial.print("Sending Temp ...");
 
  RF24NetworkHeader header(/*to node*/ other_node,/*message type*/ '2');
       
  bool ok = network.write(header,&payload,sizeof(payload));
  if (ok)
     mySerial.println("ok.");
  else
     mySerial.println("failed.");
 
}

void checkPIR()
{

val = digitalRead(PIRPIN);

  if (val == HIGH)
  {
    if (pirstate == 0)
    {
      mySerial.println("Mot");
      pirstate = 1;
      sendPIR();
    }
  } else {
    if (pirstate == 1)
    {
      mySerial.println("Mot s");
      pirstate = 0;
      sendPIR();
    }
  }

}

void checkTemp()
{

  int chk = DHT11.read(DHT11PIN);

  /*
  mySerial.print("ram ");
  mySerial.println(freeRam());
 
  mySerial.print("Humidity (%): ");
  mySerial.println(DHT11.humidity);
*/
 
  sendTemp();

}

I have created 2 message structures that are used to pass the dht11 data and the pir status. These are mirrored at the base station end where the message type is used to select the correct structure to decode the payload. It also includes a primitive scheduler so that I can vary the rate of sending each type of data.

Hope the above is helpful to you.

stan001

crofter,

I copy yr code and compiled the attiny84 codes with RF24 and RF24Network and got the following compile error...

Code: [Select]

Arduino: 1.5.5 (Windows 7), Board: "ATtiny84 @ 8 MHz  (internal oscillator; BOD disabled)"

c:/arduino-1.5.5/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../../avr/bin/ld.exe: C:\TEMP\build8578025508846758489.tmp/attiny84_RF24network.cpp.elf section .text will not fit in region text
c:/arduino-1.5.5/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../../avr/bin/ld.exe: region text overflowed by 704 bytes



hengis

Hi Guys.  I am having problems compiling Lord Maniacbug's sensornet sketch.  The problem seems to be in prinf.cpp  Where can I get an up to date copy.  It is very difficult for noobs  like me to figure out all the libraries when they are not listed on github.
On the positive side I have got 2 arduinos linked - one sending sensor data to the other.
Any help would be appreciated

crofter

Stanley,

Interesting that it won't fit when using your setup. That must mean that either the libraries you are using are producing larger code than mine or your compiler is producing larger code. I have added a routine to read an LDR using an analogue read and send the value in a new structure. The ide says the code is still only 7,284 bytes.
I notice that you are using Windows while I am using Linux .. I wonder if this makes a difference.
If you want to try some comparisons I have create a couple of sketches to test different libraries so that you can compare the size of the code produced.
The first  just uses the DHT11 library and prints out the temp and humidity.
Code: [Select]
//
//   FILE:  dht11_size_test
// PURPOSE: DHT11 library size test sketch
//

#include <TinyDebugSerial.h>
TinyDebugSerial mySerial = TinyDebugSerial(); // PB0 on attiny84

#include <dht11.h>

dht11 DHT11;

#define DHT11PIN 9

void setup()
{
  mySerial.begin(9600);
  mySerial.println("DHT11 TEST PROGRAM ");

}

void loop()
{

  int chk = DHT11.read(DHT11PIN);

  mySerial.println("Read sensor: ");
/*
  switch (chk)
  {
    case DHTLIB_OK:
Serial.println("OK");
break;
    case DHTLIB_ERROR_CHECKSUM:
Serial.println("Checksum error");
break;
    case DHTLIB_ERROR_TIMEOUT:
Serial.println("Time out error");
break;
    default:
Serial.println("Unknown error");
break;
  }
*/
  mySerial.print("Humidity (%): ");
  mySerial.println(DHT11.humidity);

  mySerial.print("Temperature (°C): ");
  mySerial.println(DHT11.temperature);

  delay(2000);
}

On my machine the IDE (1.0.5) says the sketch size is 2,588 bytes

The next sketch uses rf24 to test the rf24 and spi libraries. It is the ping_pong example modified to work on the attiny. I have left the commented code in that I used for debugging.
Code: [Select]
/*
Copyright (C) 2011 James Coliz, Jr. <maniacbug@ymail.com>

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/

/**
* Use pingpair as a simple sketch to test size of rf24 library
*
*/

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

#include <TinyDebugSerial.h>
TinyDebugSerial mySerial = TinyDebugSerial(); // PB0 on attiny84
//
// Hardware configuration
//

// Set up nRF24L01 radio on SPI bus plus pins 7 & 3

RF24 radio(7,3);

// sets the role of this unit in hardware.  Connect to GND to be the 'pong' receiver
// Leave open to be the 'ping' transmitter
const int role_pin = 9;

//
// Topology
//

// Radio pipe addresses for the 2 nodes to communicate.
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };

//
// Role management
//
// Set up role.  This sketch uses the same software for all the nodes
// in this system.  Doing so greatly simplifies testing.  The hardware itself specifies
// which node it is.
//
// This is done through the role_pin
//

// The various roles supported by this sketch
typedef enum { role_ping_out = 1, role_pong_back } role_e;

// The debug-friendly names of those roles
const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"};

// The role of the current running sketch
role_e role;

void setup(void)
{
  mySerial.begin( 9600 );    // for tiny_debug_serial
  mySerial.println("Start of setup");
  //
  // Role
  //

  // set up the role pin
  pinMode(role_pin, INPUT);
  digitalWrite(role_pin,HIGH);
  delay(20); // Just to get a solid reading on the role pin

  // read the address pin, establish our role
  if ( digitalRead(role_pin) )
    role = role_ping_out;
  else
    role = role_pong_back;

  //
  // Print preamble
  //


  mySerial.println("RF24 size test");
  mySerial.print("ROLE: ");
  mySerial.println(role_friendly_name[role]);
  //
  // Setup and configure rf radio
  //

  radio.begin();

  // optionally, increase the delay between retries & # of retries
  // radio.setRetries(15,15);

  // optionally, reduce the payload size.  seems to
  // improve reliability
  // radio.setPayloadSize(8);

  //
  // Open pipes to other nodes for communication
  //

  // This simple sketch opens two pipes for these two nodes to communicate
  // back and forth.
  // Open 'our' pipe for writing
  // Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading)

  if ( role == role_ping_out )
  {
    radio.openWritingPipe(pipes[0]);
    radio.openReadingPipe(1,pipes[1]);
  }
  else
  {
    radio.openWritingPipe(pipes[1]);
    radio.openReadingPipe(1,pipes[0]);
  }

  //
  // Start listening
  //
  // if( radio.setDataRate( RF24_250KBPS ) ) {
  //   mySerial.print( "Data rate 250KBPS set!\n\r" ) ;
  // } else {
  //   mySerial.print( "Data rate 250KBPS set FAILED!!\n\r" ) ;
  // }
  // radio.setDataRate( RF24_2MBPS ) ;
  // radio.setPALevel( RF24_PA_MAX ) ;
  radio.enableDynamicPayloads() ;
  radio.setAutoAck( true ) ;
  radio.powerUp() ;
  radio.startListening();

  //
  // Dump the configuration of the rf unit for debugging
  //

  // radio.printDetails();
  // Print out register readinds for important settings
  uint8_t rf_ch, rf_setup = 0;
  byte tx_addr[5];
  byte rx_addr[5];
 
  rf_ch = radio.getChannel();
  //radio.read_register(RF_SETUP, &rf_setup, sizeof(rf_setup));
  //radio.read_register(TX_ADDR, tx_addr, sizeof(tx_addr));
  //radio.read_register(RX_ADDR_P1, rx_addr, sizeof(rx_addr));
   
  mySerial.println();
  mySerial.println("My version 1");
  mySerial.print("RF_CH :0x");
  mySerial.println(rf_ch,HEX); 
 
//  mySerial.print("RF_SETUP :0x");
//  mySerial.println(rf_setup,HEX); 
 
//  mySerial.print("TX_ADDR :");
//  for ( int i=0;i<5;i++ ) {  // Loop 5 times, print in HEX
//  mySerial.print( tx_addr[i], HEX);
//  }
//  mySerial.println();
 
//  mySerial.print("RX_ADDR :");
//  for ( int i=0;i<5;i++ ) {  // Loop 5 times, print in HEX
//  mySerial.print( rx_addr[i], HEX);
//  }
//  mySerial.println();
 
  delay(1000);      // For serial debug to read the init config output
   
}

void loop(void)
{
  //
  // Ping out role.  Repeatedly send the current time
  //

  if (role == role_ping_out)
  {
    // First, stop listening so we can talk.
    radio.stopListening();

    // Take the time, and send it.  This will block until complete
    unsigned long time = millis();
    mySerial.print("Now sending ");
    mySerial.println(time);
    radio.write( &time, sizeof(unsigned long) );

    // Now, continue listening
    radio.startListening();

    // Wait here until we get a response, or timeout (250ms)
    unsigned long started_waiting_at = millis();
    bool timeout = false;
    while ( ! radio.available() && ! timeout )
      if (millis() - started_waiting_at > 1+(radio.getMaxTimeout()/1000) )
        timeout = true;

    // Describe the results
    if ( timeout )
    {
      mySerial.print("Failed, response timed out.");
      mySerial.print("Timeout duration: ") ;
      mySerial.println((1+radio.getMaxTimeout()/1000) ) ;
    }
    else
    {
      // Grab the response, compare, and send to debugging spew
      unsigned long got_time;
      radio.read( &got_time, sizeof(unsigned long) );

      // Spew it
      mySerial.print("Got response ");
      mySerial.print(got_time);
      mySerial.print("  round-trip delay: ");
      mySerial.println(millis()-got_time);
    }

    // Try again 1s later
    delay(1000);
  }

  //
  // Pong back role.  Receive each packet, dump it out, and send it back
  //

  if ( role == role_pong_back )
  {
    // if there is data ready
    if ( radio.available() )
    {
      // Dump the payloads until we've gotten everything
      unsigned long got_time;
      bool done = false;
      while (!done)
      {
        // Fetch the payload, and see if this was the last one.
        done = radio.read( &got_time, sizeof(unsigned long) );
      }

      // First, stop listening so we can talk
      radio.stopListening();

      // Send the final one back. This way, we don't delay
      // the reply while we wait on serial i/o.
      radio.write( &got_time, sizeof(unsigned long) );
      mySerial.print("Sent response ");
      mySerial.println(got_time);
      // Now, resume listening so we catch the next packets.
      radio.startListening();
    }
  }
}

The ide reports a size of 5,608.

I hope the above helps you determine why your code is larger.

stan001

Quote

Interesting that it won't fit when using your setup. That must mean that either the libraries you are using are producing larger code than mine or your compiler is producing larger code. I have added a routine to read an LDR using an analogue read and send the value in a new structure. The ide says the code is still only 7,284 bytes.
I notice that you are using Windows while I am using Linux .. I wonder if this makes a difference.
If you want to try some comparisons I have create a couple of sketches to test different libraries so that you can compare the size of the code produced.
The first  just uses the DHT11 library and prints out the temp and humidity.


Crofter,

Which RF24 library forks are you using ?

I knew there is one of the forks that removed all the debugging / PRINTF stuff to make the codes smaller...

Stanley


crofter

Quote
Which RF24 library forks are you using ?

I knew there is one of the forks that removed all the debugging / PRINTF stuff to make the codes smaller...


As I put in my original message I am using the fork from https://github.com/jscrane . I think the rf24 library is unmodified from the version at https://github.com/gcopeland/RF24 . The page http://maniacalbits.blogspot.co.uk/2013/04/new-rf24-driver-release-fork.html has a good description of the changes he has made.

In some tests today I found that rf24network was calling radio.printdetails() even though the print statements were not correct for attiny debugging. By commenting out this call I was able to save 232 bytes of code and some RAM as well. It may not sound much but that allowed me to add code to receive a ping and send a pong back with time stamps.

mcnobby

I couldnt get RF24 to work with ATTINY85, tried the SPI85 & RF24-85 libraries, lots of messing around and still nothing

I worry that I have got too many variations of RF24 stuff in my libraries now

I just want something that works :@(
http://www.youtube.com/user/Recovered
http://www.smartshow.lighting

crofter


I worry that I have got too many variations of RF24 stuff in my libraries now


The reason I used the jscrane libraries was because he had rf24, rf24network and spi85 all in one place so I knew (hoped) they worked together. I removed all the other versions of he libraries I had tried and just left those 3. They work fine for both the attiny and the mega2560. I'm sure other versions of the libraries will work fine as long as the versions are compatible.

tapsa

I have nano v3 and nano v4 arduinos and nRF24L01+ chips

I have now checked my connections abount ~8 times and tried different tricks over 10hour.
My problem is that I dont get even pong test to work.

Both say this in start:

Code: [Select]

RF24/examples/GettingStarted/
ROLE: Pong back
*** PRESS 'T' to begin transmitting to the other node
STATUS           = 0x0e RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=7 TX_FULL=0
RX_ADDR_P0-1     = 0xf0f0f0f0d2 0xf0f0f0f0d2
RX_ADDR_P2-5     = 0xc3 0xc4 0xc5 0xc6
TX_ADDR          = 0xf0f0f0f0d2
RX_PW_P0-6       = 0x20 0x20 0x00 0x00 0x00 0x00
EN_AA            = 0x3f
EN_RXADDR        = 0x03
RF_CH            = 0x4c
RF_SETUP         = 0x23
CONFIG           = 0x6f
DYNPD/FEATURE    = 0x00 0x00
Data Rate        = 250KBPS
Model            = nRF24L01+
CRC Length       = 16 bits
PA Power         = PA_LOW


And when I change another to ping mode it says that:
Code: [Select]

*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK
Now sending 193821...failed.
Failed, response timed out.
Now sending 195111...failed.
Failed, response timed out.
Now sending 196402...failed.
Failed, response timed out.
Now sending 197692...failed.
Failed, response timed out.




Another device does not do anything when another device try send data.
Any ideas?

crofter



Code: [Select]


RX_ADDR_P0-1     = 0xf0f0f0f0d2 0xf0f0f0f0d2
RX_ADDR_P2-5     = 0xc3 0xc4 0xc5 0xc6
TX_ADDR          = 0xf0f0f0f0d2



I find those addresses a bit odd. I am not sure exactly which example you are using but it looks like both ends of your link have the same address which is obviously wrong. In the pingpair example you have the line
Code: [Select]
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };
which gives the 2 addresses .. the pingout transmits on xxxxE1 and receives on xxxxD2 and the other end does the opposite.
If I do the test on my system I get
Code: [Select]

ROLE: Ping out
STATUS           = 0x0e RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=7 TX_FULL=0
RX_ADDR_P0-1     = 0xf0f0f0f0e1 0xf0f0f0f0d2
RX_ADDR_P2-5     = 0xc3 0xc4 0x02 0x70
TX_ADDR          = 0xf0f0f0f0e1

Hope that helps

tapsa

Looks that some times in boot it gives it wrong.
in code it is
const uint64_t pipes[2] = {  0xF0F0F0F0E1LL,0xF0F0F0F0D2LL };
I use gettingstarted sample from RF24 lib

Anyhow by code it looks that when I press T it will change it. So now I also add info print after each role change.
Code: [Select]

*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK
STATUS   = 0x0e RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=7 TX_FULL=0
RX_ADDR_P0-1     = 0xf0f0f0f0e1 0xf0f0f0f0d2
RX_ADDR_P2-5     = 0xc3 0xc4 0xc5 0xc6
TX_ADDR   = 0xf0f0f0f0e1
RX_PW_P0-6  = 0x20 0x20 0x00 0x00 0x00 0x00
EN_AA    = 0x3f
EN_RXADDR   = 0x03
RF_CH    = 0x4c
RF_SETUP  = 0x23
CONFIG   = 0x0f
DYNPD/FEATURE    = 0x00 0x00
Data Rate   = 250KBPS
Model    = nRF24L01+
CRC Length  = 16 bits
PA Power  = PA_LOW
Now sending 18038...failed.
Failed, response timed out.
Now sending 19332...failed.
Failed, response timed out.
Now sending 20622...failed.
Failed, response timed out.
Now sending 21911...failed.
Failed, response timed out.
Now sending 23200...failed.
Failed, response timed out.
Now sending 24489...failed.
Failed, response timed out.
*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK
STATUS   = 0x0e RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=7 TX_FULL=0
RX_ADDR_P0-1     = 0xf0f0f0f0d2 0xf0f0f0f0e1
RX_ADDR_P2-5     = 0xc3 0xc4 0xc5 0xc6
TX_ADDR   = 0xf0f0f0f0d2
RX_PW_P0-6  = 0x20 0x20 0x00 0x00 0x00 0x00
EN_AA    = 0x3f
EN_RXADDR   = 0x03
RF_CH    = 0x4c
RF_SETUP  = 0x23
CONFIG   = 0x0f
DYNPD/FEATURE    = 0x00 0x00
Data Rate   = 250KBPS
Model    = nRF24L01+
CRC Length  = 16 bits
PA Power  = PA_LOW




tapsa

I finally solve that problem. After ~12h debugging I notice in http://arduino-info.wikispaces.com/Nrf24L01-2.4GHz-HowTo  "but the high-power versions must have a separate 3.3V supply"
So I connect 4.7uF capacitor to 3.3v pin and wohaa it works!

sej7278

anyone tried controlling power to the nrf24l01+ off using a p-channel mosfet?

i'm doing that at the moment and it never seems to wake up again. i've tried copying the init code into the loop() from setup() but it makes no difference:

Code: [Select]

void loop(void)
{
    // power on sensors using mosfet
    digitalWrite(2,LOW);

    // init radio for writing
    radio.begin();
    radio.enableDynamicPayloads();
    radio.setAutoAck(1);
    radio.setRetries(15,15);
    radio.setDataRate(RF24_250KBPS);
    radio.setPALevel(RF24_PA_MAX);
    radio.setChannel(76);
    radio.openWritingPipe(0xF0F0F0F0E1LL);
    radio.powerUp();

    .....blah....

    // transmit
    radio.write(&txBuffer, strlen(txBuffer));
   
    // power off sensors
    radio.powerDown();
    digitalWrite(2,HIGH);

    // sleep mcu for 30secs
    Sleepy::loseSomeTime(30000);
}


i can see the power pins on the nrf24l01+ switching between 3.3v and about 0.7v (not sure why that's not exactly 0v when the fet switches off) so i assume either the rf24 doesn't like a sudden voltage drop, or there's some library calls i need to re-awaken it.

note that if i comment out the digitalWrite(2,HIGH); to turn off the fet, things work fine and my raspberry pi receives the data from the arduino.

stan001

Not sure what r u trying to achieve but the radio.powerdown and radio.powerup shd put the radio is a very low power mode..

therefore no need to off the radio...



Go Up