|
|
View previous topic :: View next topic |
Author |
Message |
mutthunaveen
Joined: 08 Apr 2009 Posts: 100 Location: Chennai, India
|
NRF24L01+ simplified working driver |
Posted: Thu May 05, 2016 10:50 am |
|
|
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
|
Yeah, it worked baby! |
Posted: Wed Jun 22, 2016 8:37 pm |
|
|
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
|
Great!! |
Posted: Wed Jun 22, 2016 10:51 pm |
|
|
thank you for sharing your feedback |
|
|
MarkchchPIC
Joined: 14 Jan 2015 Posts: 18 Location: Christchurch New Zealand
|
No Luck |
Posted: Sun Jun 26, 2016 3:26 pm |
|
|
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
|
Re: No Luck |
Posted: Sun Jun 26, 2016 4:15 pm |
|
|
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
|
|
Posted: Sun Jun 26, 2016 5:42 pm |
|
|
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
|
|
Posted: Sun Jun 26, 2016 7:08 pm |
|
|
Thanks PCM,
Could not see the wood for the trees on that one. |
|
|
championx
Joined: 28 Feb 2006 Posts: 151
|
|
Posted: Fri Jul 28, 2017 5:08 pm |
|
|
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
|
hmm |
Posted: Wed Aug 09, 2017 12:35 am |
|
|
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
|
I realize this is old post but I have a bit to add... |
Posted: Thu May 25, 2023 8:14 am |
|
|
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..
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. |
|
|
|
|
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
|