SFE Nordic nRF24L01+ module - CSN trouble

Hi,

I've been trying to interface arduino with the nRF24L01+ module from sparkfun to receive data from the SFE's Nordic fob.

I'm trying for a few days now and I can't get it to work, sometimes it will work, sometimes it won't.

Today I trimmed the problem down a bit: I know what to do to get it to work:

I have to set the manual csn pin to another one than the hardware one. Then I connect the csn pin from the module to that pin (eg 7). I plug in power, and the module configures. Than I connect csn to pin 10 (hardware csn), reset arduino, and connect the csn back to pin 7. Then it finally works. Ofcourse, this is crazy and there must be a better way. Does anyone have it working already or know enough about SPI to help me?

I'm using this library, along with the SPI library.

This is the code I'm using:

#include <Spi.h>
#include <mirf.h>
#include <nRF24L01.h>

byte data_array[4];

void setup() {
  Serial.begin(9600);
  Mirf.csnPin = 7;
  Mirf.cePin = 8;
  Mirf.init();
//  delay(50);
  byte data_array[4];
  data_array[0] = 0xE7;
  data_array[1] = 0xE7;
  data_array[2] = 0xE7;
  data_array[3] = 0xE7;
  Mirf.setRADDR(data_array);
  Mirf.configRegister(0x26,0x07); //Air data rate 1Mbit, 0dBm, Setup LNA
  Mirf.configRegister(0x21, 0x00); //Disable auto-acknowledge
  Mirf.payload = 4; //sizeof(data_array);
  Mirf.channel = 2;
  Mirf.config();
  
}

void loop(){
  if (Mirf.dataReady()){
    Serial.print("Data! : ");
    Mirf.getData(data_array);
    Serial.println(data_array[0],HEX);
    switch (data_array[0]) {
      case 0x1D: Serial.println("UP"); break;
      case 0x1E: Serial.println("DOWN"); break;
      case 0x17: Serial.println("LEFT"); break;
      case 0x1B: Serial.println("RIGHT"); break;
      case 0x0F: Serial.println("CENTER"); break;
      default: break;
    }
  }
}

Thanks in advance!

Nobody any idea?
If I had a scope I could compare pin 10's signal with pin 7's, but I don't have one.
Is there really noone else with this same module and/or problem arround?

Koen,

I have not used this module but I'm planning a project soon in the future that will. I hope you get this working and post back to the forum with what exactly you did to get this to work.

Is there any particular reason why you cant use pin 10? If that consistenly works for you, you should try that rather than using the library's optional feature. If you cant....

Also, I scanned through the code in the library and it appears quite a bit different than some of the similar libraries available online. check out these alternatives:

http://timothytwillman.com/?page_id=169

http://www.tinkerer.eu/AVRLib/nRF24L01 This one seems more geared to the avrdude ide but its the same chip so it could work

Good luck!

Hi,
The Mirf library is a port of the tinkerer.eu library actually,
and the tinkerer.eu library also uses a normal pin for CSN.
I don't know why it doesn't work, but the way above is the only way it works currently.
Just connecting to 10 from start or 7 for the whole run doesn't work.
I have been looking at the data sheet and have tried adding delayMicroseconds(10); in ceHi() and delayMicroseconds(4); in ceLow() to fix possible timing issues but it didn't help...

But... the author of the Mirf library (aarons) says on the Sparkfun forums that he has it working this thread.
Unfortunately Google apps won't receive email from sparkfun somehow so I can't register and PM him. Maybe you can...

Tonight I'll take a look at the other library, and see if that works...
The other library isn't for the nRF24L01(+) but nRF2401(A)

Never mind,
I got it working!

Here's my code:

#include <Spi.h>
#include <mirf.h>
#include <nRF24L01.h>

byte data_array[4];

void setup() {
  Mirf.csnPin = 7;
  Mirf.cePin = 8;
  Mirf.init();
//  delay(50);
  byte rx_addr[5] = {0xE7, 0xE7, 0xE7, 0xE7, 0xE7};
  Mirf.setRADDR(rx_addr);
  Mirf.configRegister(RF_SETUP, 0x07); //Air data rate 1Mbit, 0dBm, Setup LNA
  Mirf.configRegister(EN_AA, 0x00); //Disable auto-acknowledge
  Mirf.payload = 4;
  Mirf.channel = 2;
  Mirf.config();
  Serial.begin(9600);
}

void loop(){
  if (Mirf.dataReady()){
    Serial.print("Data! : ");
    Mirf.getData(data_array);
    Serial.println(data_array[0],HEX);
    switch (data_array[0]) {
      case 0x1D: Serial.println("UP"); break;
      case 0x1E: Serial.println("DOWN"); break;
      case 0x17: Serial.println("LEFT"); break;
      case 0x1B: Serial.println("RIGHT"); break;
      case 0x0F: Serial.println("CENTER"); break;
      default: break;
    }
  }
}

Yes, that was my mistake... tired eyes misread the post thought they saw a L.

I was picking through the mirf.cpp file and noticed that the address is hardcoded to length of 5. try adding another byte to your array (data_array[3] = 0xE7;)

EDIT: the above is appears to be mandatory. you must use 5 byte addressing.

A question if I may...
which command/register are you using with: Mirf.configRegister(0x21, 0x00)? i cant quite seem to find that anywhere. the closest i came up with 1d,00 but the datasheet says not to try it.

also, this just came to me... what if you just pulsed the csn line with a digitalwrite? it seems like when you move the pin physically from 7 to 10 to 7 maybe its going low and high and low (or opposite)... that could be worth a try

Thanks, calmconviction, but I already got it working.
I now have a 5byte address (but it wouldn't have mattered because I'm using the default address so I was just overwriting the first 4 bytes, and yes a 5 byte address is mandatory, but you can just change the 1st byte if you want to and leave the rest default.

Second I realized that the 0x26 and 0x21 were the commands to write to those registers, but the library expected just the register location and added 20 to it itself, so now I'm using 0x06 and 0x01 as register addresses and it's working.

So I don't have a clue why it worked after changing some pins in the first place :smiley:

Koen what are you using this for?

I have been thinking of getting some of these to make an RF Beacon for RF location tagging inside a building.

Hi Mike, I'm using this for simple remote control with the Nordic Keyfob from SFE currently. I liked the keyfob because it's reprogrammable and as it's based on the nRF24L01+, I bought a pair of tranceivers for Arduino. Yes, a pair, so I can use the tranceivers for other things than receiving the keycodes from the fob also, but I didn't try that yet.

@Mike

I'm planning on doing the same thing as you. I was inspired by the OpenBeacon project and AMD project. They used pic based tags. From what it looks like, they transmit a unique ID number, a counter (to prevent replay attacks), and the power at which the message was transmitted. All this passes through XXTEA encryption. The tags transmit the message 3 times at 3 different power levels then wait a random interval to retransmit (to prevent collisions).

I think they have an excellent design and although I'm not planning on porting it exactly to arduino but i'll be heavily borrowing their design. I gave it a pretty good search and found no one with an arduino based setup. The tags look easy to replicate but the base receivers might be a bit more challenging. the firmware is fairly similar but coding the backend to interpret rssi's to approximate radius I think could be difficult. Or it could be as simple as range testing, plotting some points in excel, then finding a regression line. I dont know. The trilateralization math isnt too challenging. I wish OpenBeacon would post a little more details of how all this data is processed. If you see any whitepapers or code or anything, please forward it here.

What type of setup are you planning on implementing?

Alex

Yes it was te OpenBeacon project that inspired me too. However, I don't need perfect accuracy or encryption. It is just a fun project to try and tag the location of my two cats inside the house and in the garden. They would wear small fobs on their collars that would house the beacons and then a selection of receivers dotted around would pick up the signals then relay them back to a central location for processing.

I'm not to familiar with the way that the FOB transmits data, but would it be possible to create a robot that moves ONLY when the corresponding button is being pressed?

Right now I have a bot made that uses this setup, however it will move in the given direction until a different key is pressed or it is actually told to stop.

Hi People, I've just noticed this thread, it looks like you've got it all sorted but if you have any more problems I'll be happy to help.

@MOS6502 it looks like the default fob firmware is programmed not to send a packet when all buttons are up. It'd be fairly easy to change this if you've got access to an ISP.

I was hoping someone would be able to help me out with a problem I'm having with a similar setup. Admittedly this wireless solution is probably a little over my head as a beginner, but I've bought the parts already, so I need to get it working.

I have purchased the same 2 sparkfun components that were discussed in this thread.

  • Nordic FOB
  • Transceiver nRF24L01+ Module with Chip Antenna

I have soldered 8 wires to the pins in the transceiver and am trying to hook up the unit to work on an Arduino Mega board. I am using the working code Koen displayed above to test it out. I have also altered the Spi.h file to change the pins correctly for the Mega. I have double checked that I have the wires connected to the correct pins, but after compiling and uploading the code to the Mega, no change occurs after pressing buttons on the FOB? As I understand it, the FOB comes ready to use, and doesn't need any changes. Am I using the correct channel? Does anything need to occur to the FOB in order for it to work w/ the transceiver. Also, I have the SS_PIN wire on the Mega, routed to the IRQ pin on the transceiver. I wasn't sure where the slave select pin should be placed (or if pin 53 even needs a jumper wire going anywhere for my simple application). I thought I read that the IRQ pin is for interruptting which shouldn't be used in my application. I guess I'm looking for ideas to help troubleshooting what my problem might be. I've looked through the Mirf functions that are getting called, and only DataReady is returning a status, which is never TRUE (1) for my case. I just don't know if that is because the FOB isn't truly sending a signal, or if the setup of the transceiver isn't correct, so it can't recieve the signal being sent.

Any ideas? Again, I'm really just a beginner that was hoping to create a wireless scoreboard display w/ SparkFun's large 7 segment displays. This is the last piece of the circuit that needs to be working before I can move from breadboarding to prototyping.

#define SCK_PIN 52
#define MISO_PIN 50
#define MOSI_PIN 51
#define SS_PIN 53

Thanks for any help.

Hello, i realise this thread is a bit old now but heres my conti
@DarrenC
no need to edit SPI.h, if like my you use Duemilanove + Mega it's a pain to keep editing SPI.h, just add this code after the 328 define

#if defined(__AVR_ATmega128__) || defined(__AVR_ATmega1280__)
  #define SCK_PIN   52
  #define MISO_PIN  50 
  #define MOSI_PIN  51
  #define SS_PIN    53
#endif

then just select Mega from Tools->Board menu and the right pins will be assigned, also here is the working code im using, it's just the mirf examples

IMPORTANT: I am using Arduino IDE 018, i've tried 019 and anything SPI i had written in 018 didn't work so for now im staying with 018

Demilanove sends reading from AN0 every second

#include <Spi.h>
#include <mirf.h>
#include <nRF24L01.h>

int l=65;
int ledPin =  8; 
void setup()
{
//  Serial.begin(9600);
    pinMode(ledPin, OUTPUT); 

  Mirf.init();
  Mirf.setRADDR((byte *)"clie1");
  Mirf.payload = sizeof(int);
  Mirf.config();

}

void loop()
{
 // byte data[Mirf.payload];
  Mirf.setTADDR((byte *)"serv1");
 
  int temp = analogRead(0);
  Mirf.send((byte *) &temp); 
  
  while(Mirf.isSending())
  {
  }

  digitalWrite(ledPin, HIGH);  
  delay(50);               
  digitalWrite(ledPin, LOW);   
  delay(950);           
}

Mega Recieves and displays byte on LCD

#include <LiquidCrystal.h>
#include <Spi.h>
#include <mirf.h>
#include <nRF24L01.h>

char buffer[50];

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

void setup()
{
  //Serial.begin(9600);
  lcd.begin(16, 2);
  Mirf.cePin = 49;
  Mirf.csnPin = 53;
  Mirf.init();
  Mirf.setRADDR((byte *)"serv1");
  Mirf.payload = sizeof(int);
  Mirf.config();

}

void loop(){
  int data;
  if(Mirf.dataReady())
  {
    //Serial.println("Got packet");
    lcd.setCursor(0, 0);
    lcd.print("Got Packet");
    
    Mirf.getData((byte *) &data);
    //Serial.println(data);
    sprintf(buffer,"%d   ", data);
    lcd.setCursor(0, 1);
    lcd.print(buffer);
  }
}