SparkFun Forums 

Where electronics enthusiasts find answers.

Your source for all things Atmel.
By sharkbits
#66383
I created an Arduino NRF2401 library which is ready to plug-n-play. Put the .h and .c files in hardware\libraries\nRF2401\.

nrf2401.h
Code: Select all
/*
Arduino based NRF2401 Header File
Created by Sam Berro -- samberro(at)gmail.com
*/

#ifndef NRF2401_H
#define NRF2401_H

#include "WConstants.h"

#ifdef __cplusplus
extern "C" {
#endif


#define RX true
#define TX false

#define kbps240 false
#define kbps1000 true

#define SHOCKBURST true
#define DIRECT false

typedef struct {
    uint8_t CE;
    uint8_t CS;
    uint8_t DR1;
    uint8_t CLK;    
    uint8_t DATA;
} nrf2401_pins_t;

extern nrf2401_pins_t nrf2401_pins; 

/* ---- nrf2401_config_t struct was adopted from Timothy Willman's implementation ---- */
typedef struct {
    uint8_t data2w;
    uint8_t data1w;
    uint8_t addr2[5];
    uint8_t addr1[5];
    
    uint8_t addrw_crc;  /* addr_w:6 crc_l:1 crc_en:1 (hi-lo) */
    uint8_t misc;        /*  rx2_en:1 cm:1 rfdr_sb:1 xo_f:3 rf_pwr:2 (hi-lo) */
    uint8_t rf_ch_rxen;  /* rf_ch:7 rxen:1 (hi-lo) */
} nrf2401_config_t;

extern nrf2401_config_t nrf2401_config;
extern nrf2401_pins_t nrf2401_pins;

/*--------- MAIN FUNCTIONS: Call these functions ----------*/
void nrf2401_Init();
boolean nrf2401_available();
void nrf2401_getPacket(uint8_t*);
void nrf2401_sendPacket(const uint8_t*, const uint8_t*);
boolean nrf2401_getOpMode();
void nrf2401_setOpMode(boolean);

/* ---------- Functions to set the config word. Need to call nrf2401_Init for changes to take effect -------*/
void nrf2401_setRX(boolean);
void nrf2401_setChnl(uint8_t);
void nrf2401_setPow(uint8_t);
void nrf2401_setFreq(uint8_t);
void nrf2401_setDRate(boolean);
void nrf2401_setCM(boolean);
void nrf2401_setRX2EN(boolean);
void nrf2401_setCRCEN(boolean);
void nrf2401_setCRC16(boolean);
void nrf2401_setADDRW(uint8_t);
void nrf2401_setADDR1(const uint8_t*);
void nrf2401_setADDR2(const uint8_t*);
void nrf2401_setData1W(uint8_t);
void nrf2401_setData2W(uint8_t);

/* ------ Helper Functions -------*/
void nrf2401_toggleByte(const uint8_t);



#ifdef __cplusplus
};
#endif

#endif /* #ifndef NRF2401_H ... */
nrf2401.c
Code: Select all
/*
Arduino based NRF2401 Header File
Created by Sam Berro -- samberro(at)gmail.com
*/

#include "nrf2401.h"

nrf2401_config_t nrf2401_config = {0x20,0x08,{0x11,0x22,0x33,0x44,0xE7},{0x11,0x22,0x33,0x44,0xE7},0xA3,0x4F,0x20};
nrf2401_pins_t nrf2401_pins = {8,9,7,10,11};

void nrf2401_setOpMode(boolean b){
  //TX = FALSE, RX= TRUE
  uint8_t i = 8;
  pinMode(nrf2401_pins.DATA,OUTPUT);
  digitalWrite(nrf2401_pins.DATA,LOW);
  digitalWrite(nrf2401_pins.CE,LOW);
  digitalWrite(nrf2401_pins.CS,HIGH);
  delayMicroseconds(500);//Tcs2data
  if(b) nrf2401_config.rf_ch_rxen |= 0x01;
  else nrf2401_config.rf_ch_rxen &= 0xFE;
  for(i=8;i>0;i--){
    digitalWrite(nrf2401_pins.DATA,((nrf2401_config.rf_ch_rxen>>(i-1)) & (0x01)));
    delayMicroseconds(1);
    digitalWrite(nrf2401_pins.CLK,HIGH);
    delayMicroseconds(1);
    digitalWrite(nrf2401_pins.CLK, LOW);
  }
  if(b == RX) pinMode(nrf2401_pins.DATA,INPUT);
  digitalWrite(nrf2401_pins.DATA,LOW);
  digitalWrite(nrf2401_pins.CLK,LOW);
  digitalWrite(nrf2401_pins.CS,LOW);
  if(b==RX) digitalWrite(nrf2401_pins.CE,HIGH);
} //setOpMode

boolean nrf2401_getOpMode(){
  return (nrf2401_config.rf_ch_rxen & 0x01);
}

void nrf2401_setRX(boolean b){
  if(b) nrf2401_config.rf_ch_rxen |= 0x01;
  else nrf2401_config.rf_ch_rxen &= 0xFE;
}

void nrf2401_setChnl(uint8_t c){
  boolean rxen =  nrf2401_config.rf_ch_rxen &= 0x01;
  nrf2401_config.rf_ch_rxen = c<<1;
  if(rxen) nrf2401_setRX(rxen);
}

void nrf2401_setPow(uint8_t p){
  nrf2401_config.misc |= (p & 0x03);
  nrf2401_config.misc &= (p | 0xFC);
}

void nrf2401_setFreq(uint8_t f){
  nrf2401_config.misc |= (f<<2 & 0x1C);
  nrf2401_config.misc &= (f<<2 | ~0x1C);
}

void nrf2401_setDRate(boolean r){
 if(r == kbps1000) nrf2401_config.misc |= 0x20;
  else nrf2401_config.misc &= ~0x20;
}

void snrf2401_setCM(boolean m){
  if(m == SHOCKBURST) nrf2401_config.misc |= 0x40;
  else nrf2401_config.misc &= ~0x40;
}

void nrf2401_setRX2EN(boolean e){
if(e) nrf2401_config.misc |= 0x80;
  else nrf2401_config.misc &= ~0x80;
}

void nrf2401_setCRCEN(boolean e){
  if(e) nrf2401_config.addrw_crc |= 0x01;
  else nrf2401_config.addrw_crc &= ~0x01;
}

void nrf2401_setCRC16(boolean c){
  if(c) nrf2401_config.addrw_crc |= 0x02;
  else nrf2401_config.addrw_crc &= ~0x02;
}

void nrf2401_setADDRW(uint8_t a){
  nrf2401_config.addrw_crc |= (a<<2 & 0xFC);
  nrf2401_config.addrw_crc &= (a<<2 | ~0xFC);
}

void nrf2401_setADDR1(const uint8_t* a1){
  uint8_t i = 0;
  for(i=0;i<5;i++){
    nrf2401_config.addr1[i] = a1[i];
  }
}

void nrf2401_setADDR2(const uint8_t* a2){
  uint8_t i = 0;
  for(i=0;i<5;i++){
    nrf2401_config.addr2[i] = a2[i];
  }
}

void nrf2401_setData1W(uint8_t w){
  nrf2401_config.data1w = w;
}

void nrf2401_setData2W(uint8_t w){
  nrf2401_config.data2w = w;
}

void nrf2401_toggleByte(uint8_t b){
  pinMode(nrf2401_pins.CLK, OUTPUT);
  pinMode(nrf2401_pins.DATA, OUTPUT);
  
  uint8_t i =0;
  for(i=0;i<8;i++){
    digitalWrite(nrf2401_pins.DATA, b & 0x80>>i);
	delayMicroseconds(1);
	digitalWrite(nrf2401_pins.CLK, HIGH);
	delayMicroseconds(1);
	digitalWrite(nrf2401_pins.CLK, LOW);
  }
}


void nrf2401_Init(){
  uint8_t i = 0;
  uint8_t arr [15] = {nrf2401_config.data2w, nrf2401_config.data1w, nrf2401_config.addr2[0], nrf2401_config.addr2[1], nrf2401_config.addr2[2],
				nrf2401_config.addr2[3], nrf2401_config.addr2[4], nrf2401_config.addr1[0], nrf2401_config.addr1[1], nrf2401_config.addr1[2],
				nrf2401_config.addr1[3], nrf2401_config.addr1[4], nrf2401_config.addrw_crc, nrf2401_config.misc, nrf2401_config.rf_ch_rxen};
  pinMode(nrf2401_pins.CLK, OUTPUT);
  pinMode(nrf2401_pins.CE, OUTPUT);
  pinMode(nrf2401_pins.CS, OUTPUT);
  pinMode(nrf2401_pins.DATA, OUTPUT);
  pinMode(nrf2401_pins.DR1,INPUT);
  
  digitalWrite(nrf2401_pins.CE,LOW);
  digitalWrite(nrf2401_pins.CS,HIGH);
  delay(3);
  for(i=0;i<15;i++){
    nrf2401_toggleByte(arr[i]);
  }
  digitalWrite(nrf2401_pins.CS,LOW);
  digitalWrite(nrf2401_pins.DATA,LOW);
  digitalWrite(nrf2401_pins.CLK,LOW);
  digitalWrite(nrf2401_pins.CE,LOW);
  if(nrf2401_config.rf_ch_rxen & 0x01){
    digitalWrite(nrf2401_pins.CE, HIGH); 
	pinMode(nrf2401_pins.DATA, INPUT);
  }
}

void nrf2401_sendPacket(const uint8_t *a, const uint8_t *d){
  if(nrf2401_getOpMode() == RX) nrf2401_setOpMode(TX);
  uint8_t i =0;
  uint8_t dlength = nrf2401_config.data1w >> 3; //length in bytes
  uint8_t alength = ((nrf2401_config.addrw_crc >> 2)&0x3F)>>3;//length in bytes
  digitalWrite(nrf2401_pins.CE, HIGH);
  delayMicroseconds(5);
  for(i=0;i<alength;i++){
    nrf2401_toggleByte(a[i]);
  }
  for(i=0;i<dlength;i++){
    nrf2401_toggleByte(d[i]);
  }
  digitalWrite(nrf2401_pins.CE,LOW);
  delayMicroseconds(200); //Tsby2rx/tx
  nrf2401_setOpMode(RX);
}

boolean nrf2401_available(){
  if(nrf2401_getOpMode() == TX) nrf2401_setOpMode(RX);
  return digitalRead(nrf2401_pins.DR1);
}

void nrf2401_getPacket(uint8_t *b){
  if(nrf2401_getOpMode() == TX) nrf2401_setOpMode(RX);
  uint8_t i = 0;
  while(nrf2401_available()){
    b[i/8] <<= 1;
	if(digitalRead(nrf2401_pins.DATA)) b[i/8] |= 0x01;
	digitalWrite(nrf2401_pins.CLK, HIGH);
    delayMicroseconds(1);
    digitalWrite(nrf2401_pins.CLK, LOW);
    delayMicroseconds(1);  
	i++;
  }
}

For test purposes I have coded a sender and a receiver. The sender operates at 1Mbps with 20Bytes payload, 5Bytes addr and 16bit CRC. The sender sends 20 byte packets stamped with a frame ID. The receiver sends an ACK once it receives a frame. This protocol insures no missed frames, and if the sender misses the ACK and resends, the rcvr knows its a resend and simply drops the frame. In my example the frame ID is simply a counter.
You can implement your own protocol, as well as set your own data rate and data width using my config functions.

Sender.c
Code: Select all
#include <nrf2401.h>

byte count = 0x00;
const int dataw = 20;
byte addr [] = {0x11,0x22,0x33,0x44,0xE7};

boolean getAck(unsigned long t){
  //t=time in ms
  byte ack[dataw] = {0};
  nrf2401_setOpMode(RX);
  unsigned long entry = millis();
  while(!nrf2401_available() && millis()<entry+t) delay(1);
  if(!nrf2401_available()) return false;
  else {
    nrf2401_getPacket(ack);
    if(ack[0] == ((count-1)&0xFF))   return true;
  }
  return false;
}

void setup() {
 nrf2401_setData1W(dataw<<3);
 nrf2401_setDRate(kbps1000);
 nrf2401_Init();
 Serial.begin(19200);
}
void loop (){
  byte pl   [] = {   count++,count<<1,
                0xE7,0x11,0x22,0x33,0x44,0x55,
                0xE7,0x11,0x22,0x33,0x44,0x55,
                0xE7,0x11,0x22,0x33,0x44,0x55};
  nrf2401_sendPacket(addr,pl);
  while(!getAck(100)){
    nrf2401_sendPacket(addr,pl);
  }
}
Rcvr.c
Code: Select all
#include <nrf2401.h>

byte temp_b_l = 0x00;
unsigned long temp = 0;
int count = 0;
int count2 = 0;
double rate = 0;
unsigned long BEST = 1000000000;
const int dataw = 20;
byte addr [] = {0x11,0x22,0x33,0x44,0xE7};

void setup(){
  Serial.begin(19200);
 nrf2401_setRX(true);
 nrf2401_setDRate(kbps1000);
 nrf2401_setData1W(dataw<<3);
 nrf2401_Init();
  pinMode(13, OUTPUT);
  pinMode(2,OUTPUT);
  temp = millis();
  
}
void loop(){
  byte temp_b[dataw] = {0};
  if(nrf2401_available()) {
    digitalWrite(13,HIGH);
    nrf2401_getPacket(temp_b);
    nrf2401_sendPacket(addr, temp_b);
    if(temp_b[0] != temp_b_l){
      //Serial.print(" 0x");
      //if(temp_b[0]<0x10) Serial.print("0");
      //Serial.print(temp_b[0], HEX);
      //Serial.print(temp_b[1], HEX);
      temp_b_l = temp_b[0];
      count++;
    }
    else {count2++;}
  }  

  if(temp_b[0] == 0xFF && count > 1){
    temp = millis()-temp;
    rate = 100*((float)(temp_b[0]-count+1)/(float)(temp_b[0]));
    if(temp < BEST){
      BEST = temp;
    }
    
    Serial.println("");
    Serial.println("--------------------------------------------------------------------");
    Serial.println("|  Sent  |  Rcvd  | Missed (Err%) | Repeated | Best Run | Last Run |");
    Serial.println("--------------------------------------------------------------------");
    Serial.print("|  ");Serial.print(temp_b[0]+1, DEC);Serial.print("   |");
    Serial.print("  ");Serial.print(count, DEC);Serial.print("   |");
    Serial.print("  ");Serial.print(temp_b[0]+1-count, DEC);Serial.print("     (");
    Serial.print(rate, DEC);Serial.print("%)   |");
    Serial.print("    ");Serial.print(count2, DEC);Serial.print("     |");
    Serial.print("  ");Serial.print(BEST, DEC);Serial.print("ms  |");
    Serial.print("  ");Serial.print(temp, DEC);Serial.println("ms  |");
    Serial.println("--------------------------------------------------------------------");
    count2=0;
    count = 0;
    temp = millis();
  }
}
The rcvr code connects to a serial term and outputs performance info. This is what I'm getting at my current settings (20 bytes data, 1Mbps) :
(Set terminal font to Courier New for best results)
Code: Select all
--------------------------------------------------------------------
|  Sent  |  Rcvd  | Missed (Err%) | Repeated | Best Run | Last Run |
--------------------------------------------------------------------
|  256   |  256   |  0     (0%)   |    1     |  4186ms  |  4397ms  |
--------------------------------------------------------------------

--------------------------------------------------------------------
|  Sent  |  Rcvd  | Missed (Err%) | Repeated | Best Run | Last Run |
--------------------------------------------------------------------
|  256   |  256   |  0     (0%)   |    2     |  4186ms  |  4398ms  |
--------------------------------------------------------------------

--------------------------------------------------------------------
|  Sent  |  Rcvd  | Missed (Err%) | Repeated | Best Run | Last Run |
--------------------------------------------------------------------
|  256   |  256   |  0     (0%)   |    4     |  4186ms  |  4606ms  |
--------------------------------------------------------------------

--------------------------------------------------------------------
|  Sent  |  Rcvd  | Missed (Err%) | Repeated | Best Run | Last Run |
--------------------------------------------------------------------
|  256   |  256   |  0     (0%)   |    1     |  4186ms  |  4291ms  |
--------------------------------------------------------------------

--------------------------------------------------------------------
|  Sent  |  Rcvd  | Missed (Err%) | Repeated | Best Run | Last Run |
--------------------------------------------------------------------
|  256   |  256   |  0     (0%)   |    0     |  4186ms  |  4186ms  |
--------------------------------------------------------------------

--------------------------------------------------------------------
|  Sent  |  Rcvd  | Missed (Err%) | Repeated | Best Run | Last Run |
--------------------------------------------------------------------
|  256   |  256   |  0     (0%)   |    2     |  4186ms  |  4397ms  |
--------------------------------------------------------------------

--------------------------------------------------------------------
|  Sent  |  Rcvd  | Missed (Err%) | Repeated | Best Run | Last Run |
--------------------------------------------------------------------
|  256   |  256   |  0     (0%)   |    2     |  4186ms  |  4606ms  |
--------------------------------------------------------------------

--------------------------------------------------------------------
|  Sent  |  Rcvd  | Missed (Err%) | Repeated | Best Run | Last Run |
--------------------------------------------------------------------
|  256   |  256   |  0     (0%)   |    2     |  4186ms  |  4502ms  |
--------------------------------------------------------------------

Remember to set the pins to however you have the avr and nRF2401 connected like this:
Code: Select all
nrf2401_pins.CE = ...
nrf2401_pins.CS = ...
nrf2401_pins.DR1=...
nrf2401_pins.CLK=...
nrf2401_pins.DATA=...
Hope this helps somebody. Enjoy.
By r55boy
#69731
Sharkbits - Thanks for the files - I am about to start using it. Are there any updates or corrections?
Fingers crossed - I will let you know how I get on.
By sharkbits
#69777
r55boy wrote:Sharkbits - Thanks for the files - I am about to start using it. Are there any updates or corrections?
Fingers crossed - I will let you know how I get on.
These files and example sketches should get you started. They were developed and tested using Arduino 0011 (which I still use). It was brought to my attention that compiling these sketches on 0014 fails at compile time, although an object file gets generated from the library.

As far as updates, I have added a lot since my last post, mainly utility functions and such. A pair of nice functions I added are a sendWithReply() and a getWithReply() which perform ACKing to make sure a packet was received on the other end. This is similar to the latest nordic wireless transceiver which implements it in hardware. Let me know if you're interested I'll be happy to provide my latest version.

Good luck.
By sharkbits
#69778
I found out there was a typo in the original code post so here are my latest .h/.c files for nrf2401:

nrf2401.h
Code: Select all
/*
Arduino based NRF2401 Header File
Created by Sam Berro -- samberro(at)gmail.com
-------------------------------------------------------
March 09 2009:
  - added new send/rcv functions that do handshaking 
  - changed default pin assignment
  - kbps240 is now kbps250
-------------------------------------------------------
*/

#ifndef NRF2401_H
#define NRF2401_H

#include "WConstants.h"

#ifdef __cplusplus
extern "C" {
#endif


#define RX true
#define TX false

#define kbps250 false
#define kbps1000 true

#define SHOCKBURST true
#define DIRECT false

typedef struct {
    uint8_t CE;
    uint8_t CS;
    uint8_t DR1;
    uint8_t CLK;    
    uint8_t DATA;
} nrf2401_pins_t;

extern nrf2401_pins_t nrf2401_pins; 

/* ---- nrf2401_config_t struct was adopted from Timothy Willman's implementation ---- */
typedef struct {
    uint8_t data2w;
    uint8_t data1w;
    uint8_t addr2[5];
    uint8_t addr1[5];
    
    uint8_t addrw_crc;  /* addr_w:6 crc_l:1 crc_en:1 (hi-lo) */
    uint8_t misc;        /*  rx2_en:1 cm:1 rfdr_sb:1 xo_f:3 rf_pwr:2 (hi-lo) */
    uint8_t rf_ch_rxen;  /* rf_ch:7 rxen:1 (hi-lo) */
} nrf2401_config_t;

extern nrf2401_config_t nrf2401_config;

/*--------- MAIN FUNCTIONS: Call these functions ----------*/
void nrf2401_Init();
boolean nrf2401_available();
void nrf2401_getPacket(uint8_t*);
void nrf2401_getPacketWithReply(uint8_t*);
void nrf2401_sendPacket(const uint8_t*, const uint8_t*);
boolean nrf2401_sendPacketWithReply(const uint8_t*, const uint8_t*,unsigned long);
boolean nrf2401_getOpMode();
void nrf2401_setOpMode(boolean);

/* ---------- Functions to set the config word. Need to call nrf2401_Init for changes to take effect -------*/
void nrf2401_setRX(boolean);
void nrf2401_setChnl(uint8_t);
void nrf2401_setPow(uint8_t);
void nrf2401_setFreq(uint8_t);
void nrf2401_setDRate(boolean);
void nrf2401_setCM(boolean);
void nrf2401_setRX2EN(boolean);
void nrf2401_setCRCEN(boolean);
void nrf2401_setCRC16(boolean);
void nrf2401_setADDRW(uint8_t);
void nrf2401_setADDR1(const uint8_t*);
void nrf2401_setADDR2(const uint8_t*);
void nrf2401_setData1W(uint8_t);
void nrf2401_setData2W(uint8_t);

/* ------ Helper Functions -------*/
void nrf2401_toggleByte(const uint8_t);



#ifdef __cplusplus
};
#endif

#endif /* #ifndef NRF2401_H ... */
nrf2401.c
Code: Select all
/*
Arduino based NRF2401 Header File
Created by Sam Berro -- samberro(at)gmail.com
-------------------------------------------------------
March 09 2009:
  - added new send/rcv functions that do handshaking 
  - changed default pin assignment
  - fixed typo (srf2401_setCM > nrf2401_setCM)
  - kbps240 is now kbps250
-------------------------------------------------------
*/

#include "nrf2401.h"

nrf2401_config_t nrf2401_config = {0x20,0x08,{0x11,0x22,0x33,0x44,0xE7},{0x11,0x22,0x33,0x44,0xE7},0xA3,0x4F,0x20};
nrf2401_pins_t nrf2401_pins = {7,6,5,4,3};

void nrf2401_setOpMode(boolean b){
  //TX = FALSE, RX= TRUE
  uint8_t i = 8;
  pinMode(nrf2401_pins.DATA,OUTPUT);
  digitalWrite(nrf2401_pins.DATA,LOW);
  digitalWrite(nrf2401_pins.CE,LOW);
  digitalWrite(nrf2401_pins.CS,HIGH);
  delayMicroseconds(500);//Tcs2data
  if(b) nrf2401_config.rf_ch_rxen |= 0x01;
  else nrf2401_config.rf_ch_rxen &= 0xFE;
  for(i=8;i>0;i--){
    digitalWrite(nrf2401_pins.DATA,((nrf2401_config.rf_ch_rxen>>(i-1)) & (0x01)));
    delayMicroseconds(1);
    digitalWrite(nrf2401_pins.CLK,HIGH);
    delayMicroseconds(1);
    digitalWrite(nrf2401_pins.CLK, LOW);
  }
  if(b == RX) pinMode(nrf2401_pins.DATA,INPUT);
  digitalWrite(nrf2401_pins.DATA,LOW);
  digitalWrite(nrf2401_pins.CLK,LOW);
  digitalWrite(nrf2401_pins.CS,LOW);
  if(b==RX) digitalWrite(nrf2401_pins.CE,HIGH);
  //delayMicroseconds(500); sometimes this seemed to save the day !!
} //setOpMode

boolean nrf2401_getOpMode(){
  return (nrf2401_config.rf_ch_rxen & 0x01);
}

void nrf2401_setRX(boolean b){
  if(b) nrf2401_config.rf_ch_rxen |= 0x01;
  else nrf2401_config.rf_ch_rxen &= 0xFE;
}

void nrf2401_setChnl(uint8_t c){
  boolean rxen =  nrf2401_config.rf_ch_rxen &= 0x01;
  nrf2401_config.rf_ch_rxen = c<<1;
  if(rxen) nrf2401_setRX(rxen);
}

void nrf2401_setPow(uint8_t p){
  nrf2401_config.misc |= (p & 0x03);
  nrf2401_config.misc &= (p | 0xFC);
}

void nrf2401_setFreq(uint8_t f){
  nrf2401_config.misc |= (f<<2 & 0x1C);
  nrf2401_config.misc &= (f<<2 | ~0x1C);
}

void nrf2401_setDRate(boolean r){
 if(r == kbps1000) nrf2401_config.misc |= 0x20;
  else nrf2401_config.misc &= ~0x20;
}

void nrf2401_setCM(boolean m){
  if(m == SHOCKBURST) nrf2401_config.misc |= 0x40;
  else nrf2401_config.misc &= ~0x40;
}

void nrf2401_setRX2EN(boolean e){
if(e) nrf2401_config.misc |= 0x80;
  else nrf2401_config.misc &= ~0x80;
}

void nrf2401_setCRCEN(boolean e){
  if(e) nrf2401_config.addrw_crc |= 0x01;
  else nrf2401_config.addrw_crc &= ~0x01;
}

void nrf2401_setCRC16(boolean c){
  if(c) nrf2401_config.addrw_crc |= 0x02;
  else nrf2401_config.addrw_crc &= ~0x02;
}

void nrf2401_setADDRW(uint8_t a){
  nrf2401_config.addrw_crc |= (a<<2 & 0xFC);
  nrf2401_config.addrw_crc &= (a<<2 | ~0xFC);
}

void nrf2401_setADDR1(const uint8_t* a1){
  uint8_t i = 0;
  for(i=0;i<5;i++){
    nrf2401_config.addr1[i] = a1[i];
  }
}

void nrf2401_setADDR2(const uint8_t* a2){
  uint8_t i = 0;
  for(i=0;i<5;i++){
    nrf2401_config.addr2[i] = a2[i];
  }
}

void nrf2401_setData1W(uint8_t w){
  nrf2401_config.data1w = w;
}

void nrf2401_setData2W(uint8_t w){
  nrf2401_config.data2w = w;
}

void nrf2401_toggleByte(uint8_t b){
  pinMode(nrf2401_pins.CLK, OUTPUT);
  pinMode(nrf2401_pins.DATA, OUTPUT);
  
  uint8_t i =0;
  for(i=0;i<8;i++){
    digitalWrite(nrf2401_pins.DATA, b & 0x80>>i);
	delayMicroseconds(1);
	digitalWrite(nrf2401_pins.CLK, HIGH);
	delayMicroseconds(1);
	digitalWrite(nrf2401_pins.CLK, LOW);
  }
}


void nrf2401_Init(){
  uint8_t i = 0;
  uint8_t arr [15] = {nrf2401_config.data2w, nrf2401_config.data1w, nrf2401_config.addr2[0], nrf2401_config.addr2[1], nrf2401_config.addr2[2],
				nrf2401_config.addr2[3], nrf2401_config.addr2[4], nrf2401_config.addr1[0], nrf2401_config.addr1[1], nrf2401_config.addr1[2],
				nrf2401_config.addr1[3], nrf2401_config.addr1[4], nrf2401_config.addrw_crc, nrf2401_config.misc, nrf2401_config.rf_ch_rxen};
  pinMode(nrf2401_pins.CLK, OUTPUT);
  pinMode(nrf2401_pins.CE, OUTPUT);
  pinMode(nrf2401_pins.CS, OUTPUT);
  pinMode(nrf2401_pins.DATA, OUTPUT);
  pinMode(nrf2401_pins.DR1,INPUT);
  
  digitalWrite(nrf2401_pins.CE,LOW);
  digitalWrite(nrf2401_pins.CS,HIGH);
  delay(3);
  for(i=0;i<15;i++){
    nrf2401_toggleByte(arr[i]);
  }
  digitalWrite(nrf2401_pins.CS,LOW);
  digitalWrite(nrf2401_pins.DATA,LOW);
  digitalWrite(nrf2401_pins.CLK,LOW);
  digitalWrite(nrf2401_pins.CE,LOW);
  if(nrf2401_config.rf_ch_rxen & 0x01){
    digitalWrite(nrf2401_pins.CE, HIGH); 
	pinMode(nrf2401_pins.DATA, INPUT);
  }
}

void nrf2401_sendPacket(const uint8_t *a, const uint8_t *d){
  if(nrf2401_getOpMode() == RX) nrf2401_setOpMode(TX);
  uint8_t i =0;
  uint8_t dlength = nrf2401_config.data1w >> 3; //length in bytes
  uint8_t alength = ((nrf2401_config.addrw_crc >> 2)&0x3F)>>3;//length in bytes
  digitalWrite(nrf2401_pins.CE, HIGH);
  delayMicroseconds(5);
  for(i=0;i<alength;i++){
    nrf2401_toggleByte(a[i]);
  }
  for(i=0;i<dlength;i++){
    nrf2401_toggleByte(d[i]);
  }
  digitalWrite(nrf2401_pins.CE,LOW);
  delayMicroseconds(300); //Tsby2rx/tx + toa
  nrf2401_setOpMode(RX);
}

boolean nrf2401_sendPacketWithReply(const uint8_t*a, const uint8_t*d,unsigned long t){
  byte ackByte = d[0];
  byte ack[20] = {0};
  nrf2401_sendPacket(a,d);
  unsigned long entry = millis();
  while(!nrf2401_available() && millis() <entry+t) {delay(1);}
  if(!nrf2401_available()) return false;
  else {
    nrf2401_getPacket(ack);
    if(ack[0] == ackByte)   return true;
  }
  return false;
}

boolean nrf2401_available(){
  if(nrf2401_getOpMode() == TX) return false;
  return digitalRead(nrf2401_pins.DR1);
}

void nrf2401_getPacket(uint8_t *b){
  if(nrf2401_getOpMode() == TX) nrf2401_setOpMode(RX);
  uint8_t i = 0;
  while(nrf2401_available()){
    b[i/8] <<= 1;
	if(digitalRead(nrf2401_pins.DATA)) b[i/8] |= 0x01;
	digitalWrite(nrf2401_pins.CLK, HIGH);
    delayMicroseconds(1);
    digitalWrite(nrf2401_pins.CLK, LOW);
    delayMicroseconds(1);  
	i++;
  }
}

void nrf2401_getPacketWithReply(uint8_t *b){
  nrf2401_getPacket(b);
  nrf2401_sendPacket(nrf2401_config.addr1, b);
}
Known issues:
- DirectMode has not been tested (may work). There are no plans to fix it - use ShockBurst only.
- Send functions use the data1w field to determine how many bytes to send.

A note about sendPacketWithReply() and getPacketWithReply():
In all my protocols I use a frameID as the first byte of the packet, which has to be different for the following packet (I use a simple counter). When you use getPacketWithReply the receiver will send an ACK packet with the same FID as the one it received. SendPacketWithReply will be waiting for a packet with that same FID. In case the ACK packet itself gets missed by the xmitter, it can simply retransmit and the receiver will drop a second packet with the same FID as the previous one. This protocol sacrifices transmission time for robustness (kinda like TCP). A raw xmit/rcv can be achieved using sendPacket and get Packet.
By r55boy
#69917
Thanks Sharkbits - I am working on this now.

One related question - in your project how did you interface the arduino and the trf-2.4g since one is 5v and one 3.3?

I am currently using 10k resistors on the arduino outputs, and a pair of transistors on the data line (which is bi-directional). I need to prove this setup yet before I start on the code side. Did you do something similar?
By etracer
#69949
It would be very useful to add your library to the Arduino Playgound. That way other users could easily find it.
By sharkbits
#70030
r55boy wrote:Thanks Sharkbits - I am working on this now.

One related question - in your project how did you interface the arduino and the trf-2.4g since one is 5v and one 3.3?

I am currently using 10k resistors on the arduino outputs, and a pair of transistors on the data line (which is bi-directional). I need to prove this setup yet before I start on the code side. Did you do something similar?
I used 5 BSS138 MOSFETS and a 3.3 voltage regulator for Vcc and Gnd. Actually I created a board that is more like an Arduino shield (plugs on top). To pull this off connect each gate to 3.3v, sources to nrf2401 i/o, and drains to 5v Arduino I/Os. I cannot see how transistors will work for a bi-directional setup.

I use this board to interface with any 3.3v device it works perfectly. I lost my Eagle schematics for this but I'm planning on creating an enhanced version soon.

Goodluck.
By sharkbits
#70031
etracer wrote:It would be very useful to add your library to the Arduino Playgound. That way other users could easily find it.
I tried but after about an hour and a half of editing the wiki and documenting my code, I hit preview and it took me to the login screen, after which all my work disappeared !!!! :cry:
By r55boy
#70253
Sharkbits - got it working! and found a neat solution for bidirectional 3.3v to 5v interfacing too - see link below.

http://www.hagtech.com/pdf/translator.pdf

Also found a solution to the compile error that I logged above - add the #include <WProgram.h>.

But - I have a problem. I have built a transmitter and a reciever and its working ok at first sending a packet every second. But after 5-60 seconds the receiver stops receiving (ie: the DR line no longer goes high). Any idea why it might work perfectly for a little time then stop?

If I reset the receiver then the problem clears and it works again for a while.

Help!
By r55boy
#70278
Problem solved - I added the line back in...

//delayMicroseconds(500); sometimes this seemed to save the day !!

and its working! Clearly the Seeduino works differently than my Nano - one seems to need this extra delay, the other is happy with or without it.

Great library Sharkbits - thankyou so much.
By Sparkles
#70289
Hello,

I am planning on buying 2 http://www.sparkfun.com/commerce/produc ... cts_id=691 Nordic trancievers. I want to buy the nRF24L01+ because of the extra range, not because of the other features.

I have searched the web but could not find a library for Arduino. Do you think the library for this tranciever will be very different from the NRF2401 library? if so then I maybe need to buy the NRF2401 tranciever using your library.

Thanks in advance.
By sharkbits
#70540
r55boy wrote:Sharkbits - got it working! and found a neat solution for bidirectional 3.3v to 5v interfacing too - see link below.
http://www.hagtech.com/pdf/translator.pdf
That should work but you need two transistors and two resistors for each bidirectional bus line. Using an enhancement mode MOSFET you only need one for each bus line (I use five for DATA, DR1, CLK, CE, and CS)..
r55boy wrote: Also found a solution to the compile error that I logged above - add the #include <WProgram.h>.
Nice I have to give that a shot. I am still using Arduino 0011 because it seems to generate the smallest hex file from sketches.
r55boy wrote: Problem solved - I added the line back in...

//delayMicroseconds(500); sometimes this seemed to save the day !!

and its working!
I remember having that same problem (which led me to add the extra delay line at the time). The delay seems to be a "workaround" for the issue but not the fix. As you see I commented it out after I figured out what was wrong. I cannot for the life of me;however, remember what was causing that now. Check your power source to Nordic.. It is definitely not the Arduino/Seeduino/Nano (or at least I dont remember that it was).
By sharkbits
#70541
Sparkles wrote:Hello,

I am planning on buying 2 http://www.sparkfun.com/commerce/produc ... cts_id=691 Nordic trancievers. I want to buy the nRF24L01+ because of the extra range, not because of the other features.

I have searched the web but could not find a library for Arduino. Do you think the library for this tranciever will be very different from the NRF2401 library? if so then I maybe need to buy the NRF2401 tranciever using your library.

Thanks in advance.
Hi Sparkles,
No this library will not work for nrf24L01 modules. The newer modules use a SPI interface instead of a two-wire like on nrf2401 (data+clk). You will have to create a new library from scratch because the data structures are different - nrf2401 uses a long config word while the nrf24L01 is register based being a SPI device.
By sharkbits
#70633
Sparkles wrote:Hi Sharkbits,

Thanks for your reply. I have found this code on the internet:

http://www.seeedstudio.com/depot/images ... F24l01.rar (SeeedStudio).

http://www.seeedstudio.com/depot/24g-rf ... p-214.html

I don't know if this code also works with the Sparkfun module (I have no programming experience)?

Maybe it can be modified?

Best regards :)
The Sparkfun module uses the same Nordic chip so the code should work. However, this code is more of a "demo" code to show that the device is alive than a functional set of APIs that you can use for your own purposes.