CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

NRF24L01+ simplified working driver

 
Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message
mutthunaveen



Joined: 08 Apr 2009
Posts: 100
Location: Chennai, India

View user's profile Send private message

NRF24L01+ simplified working driver
PostPosted: Thu May 05, 2016 10:50 am     Reply with quote

Dear friends

I'm really glad to share my working code with you all.
Code:

i used CCS SW SPI
This code implementation is with enhanced shock burst with auto acknowledgment
my compiler version is -> 4.114
also post me if you succeed


It took a long time to understand and write this code and make NRF chips work as we require, thanks for "Eduardo" driver and his post in this forum. I utilized some codes from Eduardo and also other members code from that post and developed my driver.

Few good practices when using NRF chips (in the below example you need not to do anything, you can just copy and paste it will work)
1. choose a original one (means not expensive ones but google to find which is original and which are not) there are clones in market don't buy them they are really not stable (lost hell lot of time to debug and find it).
2. 6 wires from NRF to PIC you use for bus plz don't cross over, maximum try to route them in parallel.
3. write the payload into the NRF first and then set the tx address then this chip will send the good value else some times chip is sending past payload value.
4. Flush RX or Read rx payload in order to receive new data from tx device. If rx fifo is full then next receiving cycle will not work.
5. Always use TX and RX devices same payload (number of bytes you tx should be equal to number of bytes you receive) else the RF communication will not work.

---------------------------------------------
Dears if you wish to optimize do post your code too after optimizing. Sorry for bad english in the code.
---------------------------------------------
ok, now here we dive into code, enjoy

here are the drivers basic functions
Code:

// start
init_rf()
   just to initialize the IO pins

// send data in air and get the ack that i sent
send_shock_burst(s_ad1,s_ad2,s_ad3,s_ad4,s_ad5)
   returns 1 if slave ack is received
   returns 0 if slave did not acknowledge
   returns 2 NRF chip is unstable

// prepare to listen
configure_rx(master_add1,master_add2,master_add3,master_add4,master_add5)

// check if i ve receive some data
data_in_rf()
   returns 1 if there is some data in receive buffer
   returns 0 if there no data in receive buffer

// yes if received copy from NRF and paste in PIC array
rf_read_Data()
   reads the FIFO rx buffer from nrf device and puts in RF_RCV_DATA[] array

// clear NRF RX FIFO to receive more data from air traffic   
flush_rx()
   good for beginners if they flush the RX FIFO for uninterrupted communication
   


--driver--
nrf.c
Code:

//nrf.c
// V1.0 05-05-2016

// a piece of driver i wrote for NRF which is working great with auto ack
// just finish off step1, 2 and 3 and go with example main.. this works

// FYI only one pipe used rest up to you

// step1 user preference------------
//---------------- declare slave address----------------
#define s_ad1 0xE4 // this is the remote station, so called slave
#define s_ad2 0xE4 // this is the remote station, so called slave
#define s_ad3 0xE4 // this is the remote station, so called slave
#define s_ad4 0xE4 // this is the remote station, so called slave
#define s_ad5 0xE4 // this is the remote station, so called slave
//---------------- declare slave address----------------

// step2 user preference------------
// --------------- define master addresses -----------------------
#define master_add1 0xE1 // this is the base station
#define master_add2 0xE2 // this is the base station
#define master_add3 0xE3 // this is the base station
#define master_add4 0xE4 // this is the base station
#define master_add5 0xE5 // this is the base station
// --------------- define master addresses -----------------------

// step3 user preference------------
#define PAY_LOAD_BYTES 16 // number in INTeger max 32 // number of bytes to transfer through RF


static byte RF_RCV_DATA[PAY_LOAD_BYTES]; // RF_RCV_DATA this array holds the data received wirelessly
static byte RF_TX_DATA[PAY_LOAD_BYTES]; //  RF_TX_DATA you will push the data into it to send in wireless

//-------------------------------------------------------------
#define W_REGISTER 0x20
#define R_RX_PAYLOAD 0x61
#define W_TX_PAYLOAD 0xa0
//********** DEFINE PORT NAMES

#define RF24_xfer(xdata)   bb_xfer(xdata)  //Send/receive data through SPI
#define RTX_CSN_Low()      output_low(RF24_CS)        //Controls bit Chipselect
#define RTX_CSN_High()     output_high(RF24_CS)       //Controls bit Chipselect
#define RTX_CE_Low()       output_low(RF24_CE)       //Controls bit Chipenable
#define RTX_CE_High()      output_high(RF24_CE)        //Controls bit Chipenable

//--------------------------------------------------------------
//--------------------------------------------------------------
   int1 DATA_IN_RX = 0;
//--------------------------------------------------------------
#include <STDLIB.H>
/*******************************************************************************/


void pulse_CSN()
{
    RTX_CSN_High();;
    delay_us(20);
    RTX_CSN_Low();
}

void init_rf(){
    RTX_CE_Low();
    RTX_CSN_High();
}

void flush_rx(){ // write it at uC startup
    pulse_CSN();
    //-----------
    SPI_XFER(0xe2); //Flush RX FIFO if it is not flushed during start up then NRF will not receive anymore data
    pulse_CSN();
}

void configure_tx(){

    pulse_CSN();
    SPI_XFER(0x21); // write auto-ack
    SPI_XFER(0x01);
    pulse_CSN();
    //-----------
   
    SPI_XFER(0x22); // write enable pipes total 1
    SPI_XFER(0x01);   
    pulse_CSN();
   
    SPI_XFER(0x23); //address width = 5 bytes
    SPI_XFER(0x03);
    pulse_CSN();
    //-----------
   
    SPI_XFER(0x24); // write re-tx delay = 4ms + 15 times retransmit
    SPI_XFER(0xFF);
    pulse_CSN();   
   
    SPI_XFER(0x26); //data rate = 1MB
    SPI_XFER(0x07);
    pulse_CSN();
    //-----------
    SPI_XFER(0x31);  //x byte payload defined above
    SPI_XFER(PAY_LOAD_BYTES);
    pulse_CSN();
   
    //-----------
    SPI_XFER(0x25); //set channel 2
    SPI_XFER(0x02);
   
    pulse_CSN();
   
    //-----------
    SPI_XFER(0x27); //reset all tx related interrupts
    SPI_XFER(0xBF);
    RTX_CSN_High();

}

int1 MAX_RT(){
   
   int temp_fifo_register = 0;
   pulse_csn();
   temp_fifo_register = SPI_XFER(0);
   RTX_CSN_high();

   if(bit_test(temp_fifo_register,4)){
      return(1);
   }
   else
   {   
      return(0);
   }

}

int1 rf_data_sent(){

   int temp_fifo_register = 0;
   pulse_csn();
   temp_fifo_register = SPI_XFER(0);
   RTX_CSN_high();

   if(bit_test(temp_fifo_register,5)){
      return(1);
   }
   else
   {   
      return(0);
   }
}

int send_shock_burst(byte rf_x1, byte rf_x2, byte rf_x3, byte rf_x4, byte rf_x5){ // takes total 200 ms approx
   
    int nrf_i;

    configure_tx();
   
    RTX_CE_Low();
    pulse_CSN();   
    SPI_XFER(W_REGISTER); //PTX, CRC enabled
    SPI_XFER(0x3A);
    pulse_CSN();

    //-----------
    SPI_XFER(W_TX_PAYLOAD);
    for(nrf_i=0;nrf_i<PAY_LOAD_BYTES;nrf_i++)
        {
            SPI_XFER(RF_TX_DATA[nrf_i]); //clock in payload
            //printf("%i, %c",i,RF_TX_DATA[i]);
        }

    pulse_CSN();
    //-----------
    SPI_XFER(0x30); // TX address
      SPI_XFER(rf_x1);
      SPI_XFER(rf_x2);
      SPI_XFER(rf_x3);
      SPI_XFER(rf_x4);
      SPI_XFER(rf_x5);
    pulse_CSN();

    SPI_XFER(0x2A); // Pipe 0 address
      SPI_XFER(rf_x1);
      SPI_XFER(rf_x2);
      SPI_XFER(rf_x3);
      SPI_XFER(rf_x4);
      SPI_XFER(rf_x5);
    pulse_CSN();

    //----------------
    RTX_CE_High();
    delay_us(50);
    RTX_CE_low();
   
   delay_ms(150); // just a safe delay to utilise max retransmitts
   
   if(rf_data_sent()){
      return(1);
   }
   else
   {
      if(MAX_RT()){
         return(0);
      }
      else
      {
         return(2);
      }
   }
}

void rf_read_Data()
{
    int rf_i;
    RTX_CSN_Low();

    spi_xfer(R_RX_PAYLOAD); //Read RX payload
    for(rf_i=0;rf_i<PAY_LOAD_BYTES;rf_i++)
    {   
        RF_RCV_DATA[rf_i] = spi_xfer(0x00);
        printf("%c",RF_RCV_DATA[rf_i]);
    }
    //printf("\n");
    pulse_CSN();
   
    spi_xfer(0xe2); //Flush RX FIFO
    pulse_CSN();
    //-----------
    spi_xfer(0x27); //reset all rx related ints
    spi_xfer(0xCF);
    RTX_CSN_High();
}

void configure_RX(byte rf_slave_addr1, byte rf_slave_addr2, byte rf_slave_addr3, byte rf_slave_addr4, byte rf_slave_addr5)
{
    int i_rf_rx;
    RTX_CE_Low();;
    RTX_CSN_Low();
    spi_xfer(W_REGISTER); //PRX, CRC enabled
    spi_xfer(0x3B);
    pulse_CSN();
    delay_ms(2);
    //-----------
    spi_xfer(0x21); // write auto-ack
    spi_xfer(0x01);
    pulse_CSN();
    //-----------
    spi_xfer(0x22); // write enable pipes total 1
    spi_xfer(0x01);   
    pulse_CSN();
    //-----------
    spi_xfer(0x23); //address width = 5 bytes
    spi_xfer(0x03);
    pulse_CSN();
    //-----------
    spi_xfer(0x26); //data rate = 1MB
    spi_xfer(0x07);
    pulse_CSN();
    //-----------
    spi_xfer(0x31);  //4 byte payload
    spi_xfer(PAY_LOAD_BYTES);
    pulse_CSN();
    //-----------
    spi_xfer(0x25); //set channel 2
    spi_xfer(0x02);
    pulse_CSN();

    //----------------
    spi_xfer(0x2A); //set address E7E7E7E7E7
      spi_xfer(rf_slave_addr1);
      spi_xfer(rf_slave_addr2);   
      spi_xfer(rf_slave_addr3);
      spi_xfer(rf_slave_addr4);
      spi_xfer(rf_slave_addr5);     
    pulse_CSN();

    //----------------
    spi_xfer(W_REGISTER); //PWR_UP = 1
    spi_xfer(0x3B);

    pulse_CSN();
    //-----------
    spi_xfer(0x27); //reset all rx related ints
    spi_xfer(0xCF);
    RTX_CSN_High();
    RTX_CE_High();
}

int1 data_in_rf(){

   int temp_fifo_register = 0;
   
   pulse_csn();
   spi_xfer(0x17);
   temp_fifo_register = spi_xfer(0);
   pulse_csn();   

      spi_xfer(0x27); // clear all rx related INTS
      spi_xfer(0xCF);
      RTX_CSN_high();

   if(bit_test(temp_fifo_register,0)){
      return(0);
   }
   else
   {   
      return(1);
   }
}



example master
Code:

#include <16F877A.h>
#DEVICE *=16    /*ICD=TRUE*/  PASS_STRINGS=IN_RAM    //Admite ponteiros para constantes
#fuses HS,NOWDT,NOPROTECT,NOLVP  //877A
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
// configure your pins below it is user preference
#use spi(mode = 0, DI=PIN_D0, DO=PIN_D1, CLK=PIN_D2, BITS=8, msb_first)

/*******************************************************************************/
#define  RF24_CS        PIN_D4   //RC1;  chipselect nRF24L01+
#define  RF24_CE        PIN_D5   //RC2;  chipEnable nRF24L01+
#define  RF24_IRQ       PIN_C3    // interrupt pin
/*******************************************************************************/

/*******************STATUS LED DEFINE**************************************/
#define  alive               PIN_B2   //
#define  rf_data_sent_led        PIN_B1   // 100ms blink if data sent successfully, continious ON if data is not sent successfully
/*******************************************************************************/


#include <nrf.c>

void set_data(){ // this is the transmit array where you can put your data to transmit on air
   
   RF_TX_DATA[0] = 0x30; // ascii 0
   RF_TX_DATA[1] = 0x31; // 1
   RF_TX_DATA[2] = 0x32; // 2
   RF_TX_DATA[3] = 0x33; // 3
   RF_TX_DATA[4] = 0x34; // 4
   RF_TX_DATA[5] = 0x35; // 5
   RF_TX_DATA[6] = 0x36; // 6
   RF_TX_DATA[7] = 0x37; // 7
   RF_TX_DATA[8] = 0x38; // 8
   RF_TX_DATA[9] = 0x39; // 9
   RF_TX_DATA[10] = 0x41; // A
   RF_TX_DATA[11] = 0x42; // B
   RF_TX_DATA[12] = 0x43; // C
   RF_TX_DATA[13] = 0x44; // D
   RF_TX_DATA[14] = 0x45; // E
   RF_TX_DATA[15] = 0x46; // F
   
}

void main()
{

 init_rf();
 flush_rx(); // i use this to avoid confusion for beginers
 
while(1){

output_toggle(alive); // this toggle is just to see if the uc is alive

   delay_ms(2000);
 
   if(send_shock_burst(s_ad1,s_ad2,s_ad3,s_ad4,s_ad5)==1){
      output_high(rf_data_sent_led);
      delay_ms(100);
      output_low(rf_data_sent_led);
      }
      else
      {
      output_high(rf_data_sent_led);
      }
   
   configure_rx(master_add1,master_add2,master_add3,master_add4,master_add5); // after transmission you better configure to rx if your device needs to listen the incoming traffice if required.

   delay_ms(1000);
   
}
}


example slave
Code:

#include <16F877A.h>
#DEVICE *=16    /*ICD=TRUE*/  PASS_STRINGS=IN_RAM    //Admite ponteiros para constantes
#fuses HS,NOWDT,NOPROTECT,NOLVP  //877A
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
// configure your pins below it is user preference
#use spi(mode = 0, DI=PIN_D0, DO=PIN_D1, CLK=PIN_D2, BITS=8, msb_first)

/*******************************************************************************/
#define  RF24_CS        PIN_D4   //RC1;  chipselect nRF24L01+
#define  RF24_CE        PIN_D5   //RC2;  chipEnable nRF24L01+
#define  RF24_IRQ       PIN_C3    // interrupt pin
/*******************************************************************************/

/*******************STATUS LED DEFINE**************************************/
#define  alive               PIN_B2   //
#define  rf_data_received_led        PIN_B1   // 100ms blink if data received from air

/*******************************************************************************/

#include <nrf.c>

void main()
{

/****************RF CODE********************************/
    init_rf();
    flush_rx();
    configure_rx(s_ad1,s_ad2,s_ad3,s_ad4,s_ad5);
    delay_ms(10);
/****************RF CODE********************************/

while(TRUE){
 
  output_toggle(alive); // this toggle is just to see if the uc is alive
  delay_ms(100);

/****************RF CODE********************************/
   if(!input(RF24_IRQ)){
      if(data_in_rf()){
      delay_ms(500); // don't know why this delay.. but this is required did not debug more no time.. :)
         rf_read_Data(); // this function will print data in serial printf command
       output_high(rf_data_received_led);
       delay_ms(100);
       output_low(rf_data_received_led);
     }
   }
/****************RF CODE********************************/
}
}


i hope you will find it really useful...

----edited-----
Corrected the bugs identified by PCM.
Thank you PCM.


Last edited by mutthunaveen on Sun Jun 26, 2016 11:29 pm; edited 1 time in total
Titchomery



Joined: 13 May 2016
Posts: 2
Location: Vitória, Espírito Santo, Brazil

View user's profile Send private message

Yeah, it worked baby!
PostPosted: Wed Jun 22, 2016 8:37 pm     Reply with quote

Congratulations!

Great code.

Simple and Effective.

It was really useful to me.

The initial flush and the address setting after the payload made the difference, I guess.

Thank You for the code.
mutthunaveen



Joined: 08 Apr 2009
Posts: 100
Location: Chennai, India

View user's profile Send private message

Great!!
PostPosted: Wed Jun 22, 2016 10:51 pm     Reply with quote

thank you for sharing your feedback Cool Cool
MarkchchPIC



Joined: 14 Jan 2015
Posts: 18
Location: Christchurch New Zealand

View user's profile Send private message

No Luck
PostPosted: Sun Jun 26, 2016 3:26 pm     Reply with quote

Hi there,
I have spent a few hours this weekend trying to compile your code without success so far.
I am using version 4.071 of the compiler.
I keep getting this message:

"This type can not be qualified with this qualifier"
beside the int1 rf_data_sent() line.

Maybe my version is too old?
Can you give any advice please.

Cheers

Mark
Titchomery



Joined: 13 May 2016
Posts: 2
Location: Vitória, Espírito Santo, Brazil

View user's profile Send private message

Re: No Luck
PostPosted: Sun Jun 26, 2016 4:15 pm     Reply with quote

MarkchchPIC wrote:
Hi there,
I have spent a few hours this weekend trying to compile your code without success so far.
I am using version 4.071 of the compiler.
I keep getting this message:

"This type can not be qualified with this qualifier"
beside the int1 rf_data_sent() line.

Maybe my version is too old?
Can you give any advice please.

Cheers

Mark


I got this message too... But I don't remember exactly what I did to solve... It didn't include changing the compiler version.

I think I changed the functions order and the '#include "nfc.c"' in my main.c...
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Jun 26, 2016 5:42 pm     Reply with quote

That's not it. The problem is caused by him using 'rf_data_sent' as a
function name and in a #define statement. That's a bug.
To fix the problem, do the following things:

1. Edit the #define statement to add '_led' on the end. This will give
the #define statement a unique name. See below, as shown in bold:
Quote:
/**********STATUS LED DEFINE************/
#define alive PIN_B2 //
#define rf_data_sent_led PIN_B1

2. Then go down in main() and edit the three lines of code that turn the
LED on/off. Add '_led' to end of 'rf_data_sent' in each line, as shown
in bold below:
Quote:

if(send_shock_burst(s_ad1,s_ad2,s_ad3,s_ad4,s_ad5)==1){
output_high(rf_data_sent_led);
delay_ms(100);
output_low(rf_data_sent_led);
}
else
{
output_high(rf_data_sent_led);
}


Also, he has a 'Subscript out of range' error when compiling. That's
because his RF_TX_DATA[] array has a size of 15 bytes, which means
it has elements from 0 to 14, but he is writing to element 15 which
doesn't exist. To fix this, comment out the last line in the set_data()
function as shown in bold below:
Quote:
void set_data(){
RF_TX_DATA[0] = 0x30; // ascii 0
RF_TX_DATA[1] = 0x31; // 1
RF_TX_DATA[2] = 0x32; // 2
RF_TX_DATA[3] = 0x33; // 3
RF_TX_DATA[4] = 0x34; // 4
RF_TX_DATA[5] = 0x35; // 5
RF_TX_DATA[6] = 0x36; // 6
RF_TX_DATA[7] = 0x37; // 7
RF_TX_DATA[8] = 0x38; // 8
RF_TX_DATA[9] = 0x39; // 9
RF_TX_DATA[10] = 0x41; // A
RF_TX_DATA[11] = 0x42; // B
RF_TX_DATA[12] = 0x43; // C
RF_TX_DATA[13] = 0x44; // D
RF_TX_DATA[14] = 0x45; // E
// RF_TX_DATA[15] = 0x46; // F
}
MarkchchPIC



Joined: 14 Jan 2015
Posts: 18
Location: Christchurch New Zealand

View user's profile Send private message

PostPosted: Sun Jun 26, 2016 7:08 pm     Reply with quote

Thanks PCM,
Could not see the wood for the trees on that one.
championx



Joined: 28 Feb 2006
Posts: 151

View user's profile Send private message

PostPosted: Fri Jul 28, 2017 5:08 pm     Reply with quote

Great driver! very simple!

I have been using it for a few weeks, but i have a little problem once in a while...

Sometimes when i receive data, the buffer is empty... I reduced the delay on the IRQ function, from 500ms to 10ms. Could that be the cause?

I need to receive data with the least delay possible, so i need to reduce this delay.

thanks!
mutthunaveen



Joined: 08 Apr 2009
Posts: 100
Location: Chennai, India

View user's profile Send private message

hmm
PostPosted: Wed Aug 09, 2017 12:35 am     Reply with quote

Thanks for the feedback.

Plz check if there is a false interrupt occuring across HW IRQ signal.
(or) both HW and SW are creating IRQ and when you read, data is not there??

Rreducing delay from 500ms to 10ms,
I'm not sure why i chose 500ms at the time of development.

That was the first time i worked on NRF and not satisfied wtih coverage distance and left it.

Post back if you find the solution.

Thank you.
link555



Joined: 29 Jul 2010
Posts: 14
Location: North Vancouver

View user's profile Send private message

I realize this is old post but I have a bit to add...
PostPosted: Thu May 25, 2023 8:14 am     Reply with quote

Thank you for posting this Mutthunaveen, it has helped me greatly. I have now spent quite a bit of time testing and tweaking. One ah moment I had in my own code revolves around this section in your code:
/****************RF CODE********************************/
if(!input(RF24_IRQ)){
if(data_in_rf()){
delay_ms(500); // don't know why this delay.. but this is required did not debug more no time.. Smile
rf_read_Data(); // this function will print data in serial printf command
output_high(rf_data_received_led);
delay_ms(100);
output_low(rf_data_received_led);
}
}
/****************RF CODE********************************/

I found the if statement caused my code to miss transmissions. Instead I choose to wait for IRQ to low, I changed the section below and removed the unknow delay.

/****************RF CODE********************************/
While (input(RF24_IRQ))
{
}
if(data_in_rf())
{
rf_read_Data(); // this function will print data in serial printf command
output_high(rf_data_received_led);
delay_ms(100);
output_low(rf_data_received_led);
}
/****************RF CODE********************************/

This forces the pic to "sit and spin" until it receives the next data packet. Which works in my case because only my master controller is requesting data from one slave at a time. I was initially having trouble with slave talking at the same time. This change helped me clean up the multi-broadcast issue.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group