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
/*
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
/*
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
#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
#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)
--------------------------------------------------------------------
| 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:
nrf2401_pins.CE = ...
nrf2401_pins.CS = ...
nrf2401_pins.DR1=...
nrf2401_pins.CLK=...
nrf2401_pins.DATA=...
Hope this helps somebody. Enjoy.