Interfacing nrf24l01 with a PIC18F462/ brennen?

Hi everyone,

I’m using brennen’s C librarys to make a communication work between two PIC 18F4620. I get some problems when I run my code: it doesn’t work.

I wrote the receive code and the transmit code, the way it is told in the tutuorial1 . I’m using Microchip C18 compiler and my code is building OK. At the end of the post I show my receive code.

I configured the pins as followed and I think maybe I made something wrong???( the Chip Select CSN has to be on RA3 to match my hardware)

#define nrf24l01_CE_IOREGISTER		TRISA
#define nrf24l01_CE_PINMASK			PORTAbits.RA1

#define nrf24l01_CSN_IOREGISTER		TRISA
#define nrf24l01_CSN_PINMASK		PORTAbits.RA3

#define nrf24l01_IRQ_IOREGISTER		TRISA
#define nrf24l01_IRQ_PINMASK		PORTAbits.RA2

I wrote the SPI function and the delays functions as followed:

unsigned char spi_send_read_byte(unsigned char byte)

{
	volatile char dummy;
	char x;

	dummy = SSPBUF;		// force clearance of buffer full flag
	SSPBUF = byte;
	while (!SSPSTATbits.BF)
		;
	
	x = ReadSPI();
	
}
void delay_us(unsigned int microseconds)

{
	int i;
	for(i=0 ; i<= microseconds;i++)

		{
			Delay1TCY();
			Delay1TCY();
		}

}

When I run the program it is stuck in the spi_send_read_byte() function at the following line:while (!SSPSTATbits.BF). It doesn’t pass the nrf_initialize_debug() function.

I think maybe I didn’t initialise the SPI module of my MCU?

If anyone could help me it would be nice :slight_smile:

Thank you very much

Gregory

Here is the main code:

#include "nrf24l01.h"
#include <p18f4620.h>
#include <usart.h>
#include <stdio.h>


void main (void)

{
	
	unsigned char byte = 0x00;
	unsigned char status = 0x00;
	
	//Initialise l'Horloge à 8 MHZ

	OSCCONbits.IRCF1=1;
	OSCCONbits.IRCF0=1;

	OpenUSART( 
	USART_TX_INT_OFF &
	USART_RX_INT_OFF &
	USART_ASYNCH_MODE &
	USART_EIGHT_BIT &
	USART_CONT_RX &
	USART_BRGH_HIGH,
	51 );//9600 bauds COM 4

	printf("Debut de la Routine de reception\r\n");

	nrf24l01_initialize_debug(true,0x01,false);
	
	printf("En attente de reception");

	while(! (nrf24l01_irq_pin_active()&&nrf24l01_irq_rx_dr_active()));

	status = nrf24l01_read_rx_payload(&byte,0x01);
	printf("Octet reçus, enregistrement dans l'EEPROM");

	EECON1bits.EEPGD = 0;
	EECON1bits.CFGS = 0; 
	EECON1bits.WREN = 1; 
	EEADR = 0x00; 
	EEDATA = byte; 
	EECON2 = 0x55; 
	EECON2 = 0xaa; 
	EECON1bits.WR = 1;			//detail Nombre de Cycles ?
	while (!PIR2bits.EEIF);
	PIR2bits.EEIF = 0; 
	
	printf("Enregistrement effectué, voir à l'adresse 0");
	
	nrf24l01_irq_clear_all();
	
	while(1);

}

#define nrf24l01_CE_IOREGISTER TRISA

#define nrf24l01_CE_PINMASK PORTAbits.RA1

#define nrf24l01_CSN_IOREGISTER TRISA

#define nrf24l01_CSN_PINMASK PORTAbits.RA3

#define nrf24l01_IRQ_IOREGISTER TRISA

#define nrf24l01_IRQ_PINMASK PORTAbits.RA2

You can’t define the pinmasks this way. Since TRISA is 8 bits wide, RA1 would be 0x02 (think of the binary value which is b’00000010’), RA2 would be 0x04, and RA3 would be 0x08. That would change your code to

#define nrf24l01_CE_IOREGISTER      TRISA 
#define nrf24l01_CE_PINMASK         0x02

#define nrf24l01_CSN_IOREGISTER      TRISA 
#define nrf24l01_CSN_PINMASK      0x08

#define nrf24l01_IRQ_IOREGISTER      TRISA 
#define nrf24l01_IRQ_PINMASK      0x04

Also, int your spi_send_read_byte function, you need to return x at the end.

Try those fixes and let me know if it gets it to working for you. Interestingly enough, I am working on getting the library ported over to an 18F452 right now, so hopefully I’ll have the code working in the next few days.

Hi,

Thank you for your tips. I changed the pin definitions as you told me and put a " return x;" at the end of my SPI function.

I also initiated the SPI module and disabled A/D converter and put all pins in ADCON1 digital. (SPI: Master mode, FOSC/64). I also defined the PORTC (where the SDO,SDI and SDK are) this way:

TRISC= 0b00010000 (SDI as input, sdo as output and SCK as output)

The program passes the nrf24l01_initialize_debug() Ok

It is then stuck at the

while(! (nrf24l01_irq_pin_active()&&nrf24l01_irq_rx_dr_active()));

instruction.

So I tried to send a byte (0x31) with my other MCU where I have the transmitter (I did the same changes to the transmitter program and the program gets to pass the initialize instruction Ok).

The order is : I run the receiver code on the first MCU and then after 1 or 2 sec I run the tranmit code on the other.

The problem is that the transmitter won’t pass the

while(! (nrf24l01_irq_pin_active()&&nrf24l01_irq_tx_ds_active()));

instruction either.

Do you have any idea? it seems that nothing tranmits!

Thank you

Gregory

Here is the receiver code:

#include "nrf24l01.h"
#include <usart.h>
#include <stdio.h>

#include "SD_Utils.h"


void init_pic(void)
{

 It initiates the pin I/O for PORTB, PORTC, PORTD, PORTE
 
}

void main (void)

{
	
	unsigned char byte = 0x00;
	unsigned char status = 0x00;
	
	//Initialise l'Horloge à 8 MHZ

	OSCCONbits.IRCF1=1;
	OSCCONbits.IRCF0=1;

	init_pic();

	//Desactive A/D

	ADCON0bits.ADON=0;
	ADCON1=0b00001111;

	//Active le module SPI

	//Paramètres SSPSTAT

	SSPSTATbits.SMP=0;
	SSPSTATbits.CKE=1;

	//Paramètres SSPCON1

	SSPCON1=0x22; // FOSC/64
	PIR1bits.SSPIF = 0; //On enlève le Flag d'interruption

	OpenUSART( 
	USART_TX_INT_OFF &
	USART_RX_INT_OFF &
	USART_ASYNCH_MODE &
	USART_EIGHT_BIT &
	USART_CONT_RX &
	USART_BRGH_HIGH,
	51 );//9600 bauds COM 4

	printf("Debut de la Routine de reception\r\n");

	nrf24l01_initialize_debug(true,0x01,false);
	
	printf("En attente de reception");

	while(! (nrf24l01_irq_pin_active()&&nrf24l01_irq_rx_dr_active()));

	status = nrf24l01_read_rx_payload(&byte,0x01);
	printf("Octet reçus, enregistrement dans l'EEPROM");

	EECON1bits.EEPGD = 0;
	EECON1bits.CFGS = 0; 
	EECON1bits.WREN = 1; 
	EEADR = 0x00; 
	EEDATA = byte; 
	EECON2 = 0x55; 
	EECON2 = 0xaa; 
	EECON1bits.WR = 1;			//detail Nombre de Cycles ?
	while (!PIR2bits.EEIF);
	PIR2bits.EEIF = 0; 
	
	printf("Enregistrement effectué, voir à l'adresse 0");
	
	nrf24l01_irq_clear_all();
	
	while(1);

}

here is the transmitter code:

#include "nrf24l01.h"
#include <stdio.h>
#include <usart.h>
#include "SD_Utils.h"


void init_pic(void)

void main (void)

{
	
	unsigned char status = 0x00;
	
	unsigned char data=0x00;
	//unsigned char *pdata=&data;
	
	//Initialise l'Horloge à 8 MHZ

	OSCCONbits.IRCF1=1;
	OSCCONbits.IRCF0=1;

	init_pic();

	//Desactive A/D

	ADCON0bits.ADON=0;
	ADCON1=0b00001111;

	//Active le module SPI

	//Paramètres SSPSTAT

	SSPSTATbits.SMP=0;
	SSPSTATbits.CKE=1;

	//Paramètres SSPCON1

	SSPCON1=0x22; // FOSC/64
	PIR1bits.SSPIF = 0; //On enlève le Flag d'interruption

	
	OpenUSART( 
	USART_TX_INT_OFF &
	USART_RX_INT_OFF &
	USART_ASYNCH_MODE &
	USART_EIGHT_BIT &
	USART_CONT_RX &
	USART_BRGH_HIGH,
	51 );//9600 bauds COM 4
	
	data = 0x31;

	printf("Debut de l'envoi");

	nrf24l01_initialize_debug(false,8,true);

	status = nrf24l01_write_tx_payload(&data,8,true);
	
	TRISEbits.TRISE0=0;
	PORTEbits.RE0=1;
	
	while(! (nrf24l01_irq_pin_active()&&nrf24l01_irq_tx_ds_active()));
	printf("Fin de l'envoi");

	while(1);

}

[/code]

Ok, let’s start small here. Have you verified your SPI code using a loopback? Without having the 24L01 hooked up, you should be able to connect your SO to your SI pin and then send a byte on SO and read it from SI. If you can read the same byte you sent, then your SPI is probably working. Also, have you made sure that your printf function is printing characters to the screen?

I noticed in the first message you said, “When I run the program it is stuck in the spi_send_read_byte() function at the following line:while (!SSPSTATbits.BF). It doesn’t pass the nrf_initialize_debug() function.” That immediately tells me that you aren’t setting up the SPI right. You should run the function nrf24l01_get_all_registers to read the config after you write it (the function takes a char array of size 36 bytes). Then, loop through the values using printf, like this:

unsigned char buffer[36];
unsigned int count;

nrf24l01_get_all_registers(buffer);

for(count = 0; count < 36; count++)
    printf("%x: %x\r\n", count, buffer[count]);

This will show the values of all the registers. The annoying part is that once you hit a multi-byte register, the numbering will be off, but you will still see the correct byte order on the bytes. If you can get this function working such that it shows the correct byte values of all the registers, then you should have no problem talking to the 24L01. Verify the output with the default values shown in the 24L01 user manual (the CONFIG and RX_PW_P0 registers will be slightly different from the default values).

The only thing that wouldn’t work if you have this working would be your pin setup on your IRQ pin and possibly your CE pin. Once you get CE functioning properly, you can take out the nrf24l01_irq_pin_active() function call in the while loop and just wait on the proper interrupt in the status register using nrf24l01_irq_rx_dr_active() (for the RX) or nrf24l01_irq_tx_ds_active() (for the TX). When this functions properly, add the call to nrf24l01_irq_pin_active() back into the busy loop condition, and if you still function properly, everything is gravy. If not, you don’t have your IRQ pin setup properly in either the PIC’s registers or in the nrf24l01.h file.

Hi Brennen,

After a long try out I’m finally still in troubles!

My SPI is working: it works for a program to interface a SD for example, so I “Think” that my SPI send read code might work on your code too.

In fact it is passing the

nrf24l01_initialize_debug(true,1,false);

line.

I made a print of the registers: I get only 0’s! and even if the module is not connected.

The funny thing is that on a test wednesday I had other numbers than 0’ in the register and I started to “see” a transmission. When I commented out the nrf24l01_irq_pin_active() instruction in

while(!(nrf24l01_irq_pin_active() && nrf24l01_irq_rx_dr_active()));

There was nothing on the screen at first (still Ok) and then I ran the transmit code on an other PIC and I got 0’ on the USART. If I stopped the transmit code no more 0’s on the screen and when I ran again they would come back!

So I don’t know what happened since this moment because it isn’t working anymore! it is as if the nrf module wasn’t there at all! Could It be software related?

Here is my receive code:

If you have any Idea? did it work on the p18f452?

Thanks a lot

Gregory

#include "nrf24l01.h"
#include <p18f4620.h>
#include <usart.h>
#include <stdio.h>


#pragma config OSC = INTIO67

#define	PC_DefData	0b00000001
#define	PC_DefTRIS	0b00010000
		// 7   Rien
		// 6   Rien
		// 5   SDO
		// 4   SDI
		// 3   SCK
		// 2   Rien
		// 1   Rien 	
		// 0   Rien

void main (void)

{
	unsigned int i;
	unsigned char byte;
	unsigned char status[36];
	unsigned char Msg[6];
	
	//Initialise l'Horloge à 8 MHZ

	OSCCONbits.IRCF1=1;
	OSCCONbits.IRCF0=1;

	//Desactive A/D

	ADCON0bits.ADON=0;
	ADCON1=0b00001111;

	//SPI I/O definitions:
	PORTC = PC_DefData;
	TRISC = PC_DefTRIS;

	//CE (input)  IRQ(input) CSN(output)

	TRISAbits.TRISA1=1;
	PORTAbits.RA1=1;

	TRISAbits.TRISA2=1;
	PORTAbits.RA2=1;

	TRISAbits.TRISA3=0;
	PORTAbits.RA3=1;

	//Active le module SPI

	//Paramètres SSPSTAT

	SSPSTATbits.SMP=0;
	SSPSTATbits.CKE=1;

	//Paramètres SSPCON1

	SSPCON1=0x22; // FOSC/64
	PIR1bits.SSPIF = 0; //On enlève le Flag d'interruption

	OpenUSART( 
	USART_TX_INT_OFF &
	USART_RX_INT_OFF &
	USART_ASYNCH_MODE &
	USART_EIGHT_BIT &
	USART_CONT_RX &
	USART_BRGH_HIGH,
	51 );//9600 bauds COM 4

	printf("Debut de la Routine de reception\r\n");

	nrf24l01_initialize_debug(true,1,false);
	
	nrf24l01_get_all_registers(status);

	for(i=0;i<36;i++)

	{
	
		printf("%x|",status[i]);

	}

	printf("En attente de reception\r\n");

while(1)

{	

	while(!(nrf24l01_irq_pin_active() && nrf24l01_irq_rx_dr_active()));

	nrf24l01_read_rx_payload(&byte,1);
			
	
	nrf24l01_irq_clear_all();


}
	
}
```

```

Sorry I made a mistake

When I run the nrf_get_all_registers I get

ff|ff|ff|ff|ff|ff| (…) on the USART 36 times

If you can’t get nrf24l01_get_all_registers() to work, then I can just about promise you that you’re not doing something right. I have code that is working on transmit and can read the registers now. I’m not getting transmissions through and I think it’s possibly because I have a lot of WiFi signals around me. I moved to a different apartment complex and I can’t even get the LPC2148’s to talk anymore with the same code that used to work.

Here is my main code to use nrf24l01_get_all_registers() (set up as a TX):

#include <p18f452.h>
#include <stdio.h>
#include <usart.h>
#include <spi.h>
#include "delays.h"
#include "nrf24l01.h"

void Initialize(void);
void InitializeIO(void);

void ToggleLED(void);

void main(void)
{
	unsigned char buffer[36]; 
	unsigned int count; 
	
	Initialize(); //initialize IO, UART, SPI, set up nRF24L01 as TX
	
	nrf24l01_get_all_registers(buffer); 
	
	for(count = 0; count < 36; count++) 
	    printf("%x: %x\r\n", count, buffer[count]); 
	    
	while(1);
}

void Initialize(void)
{
	InitializeIO();
	OpenUSART (USART_TX_INT_OFF & USART_RX_INT_OFF & USART_ASYNCH_MODE & USART_EIGHT_BIT & USART_CONT_RX & USART_BRGH_LOW, 64);
	OpenSPI(SPI_FOSC_16, MODE_00, SMPMID);
	nrf24l01_initialize_debug(false, 1, false);
}

void InitializeIO(void)
{
	ADCON1 = 0x7;
	TRISAbits.TRISA0 = 0;
	PORTAbits.RA0 = 1;
	
	TRISBbits.TRISB0 = 0;
	
	TRISC = 0x91;
	PORTC = 0x04;
}	

void ToggleLED(void)
{
	PORTAbits.RA0 = ~PORTAbits.RA0;
}

Here is the SPI function:

#include <spi.h>
#include <p18f452.h>

unsigned char spi1_send_read_byte(unsigned char byte)
{
	SSPBUF = byte;
	
	while(!DataRdySPI());
	
	return SSPBUF;
}

Here are my delays:

#include "delays.h"
#include <delays.h>

void DelayUS(unsigned long microseconds)
{
	unsigned long count;
	
	for(count = 0; count < microseconds; count++)
		Delay10TCY();
}

void DelayMS(unsigned long milliseconds)
{
	unsigned long count;
	
	for(count = 0; count < milliseconds; count++)
		Delay10KTCYx(1);
}

void DelayS(unsigned long seconds)
{
	unsigned long count;
	
	for(count = 0; count < seconds; count++)
	{
		Delay10KTCYx(250);
		Delay10KTCYx(250);
		Delay10KTCYx(250);
		Delay10KTCYx(250);
	}
}

Here are my definitions in nrf24l01.h:

#include <p18f452.h>

//defines for uC pins CE pin is connected to
//This is used so that the routines can send TX payload data and 
//	properly initialize the nrf24l01 in TX and RX states.
//Change these definitions (and then recompile) to suit your particular application.
#define nrf24l01_CE_IOREGISTER	PORTC
#define nrf24l01_CE_PINMASK		0x02

//defines for uC pins CSN pin is connected to
//This is used so that the routines can send properly operate the SPI interface
// on the nrf24l01.
//Change these definitions (and then recompile) to suit your particular application.
#define nrf24l01_CSN_IOREGISTER	PORTC
#define nrf24l01_CSN_PINMASK		0x04

//defines for uC pins IRQ pin is connected to
//This is used so that the routines can poll for IRQ or create an ISR.
//Change these definitions (and then recompile) to suit your particular application.
#define nrf24l01_IRQ_IOREGISTER	PORTB
#define nrf24l01_IRQ_PINMASK		0x01

I should probably also add that I’m using a 10 Mhz crystal but using the PLL to multiply that up to 40 MHz. The delays, SPI rate, and UART rate are based on this calculation. With things as-is, the SPI is running at 2.5 Mbps (Fosc/16 mode, 40MHz/16 = 2.5 MHz on serial clock).

I just wanted to note that I have two PICs now talking via the nRF24L01 with my library! :smiley: The support code that I showed above works, and below I will add the full main code for both TX and RX. All you may have to change is the delay lengths, SPI and UART rates, and the register defines in nrf24l01.h. The main files below are actually the code for my Tutorial 1, simply translated for use with my PIC boards.

TX main:

#include <p18f452.h>
#include <stdio.h>
#include <usart.h>
#include <spi.h>
#include "delays.h"
#include "nrf24l01.h"

void Initialize(void);
void InitializeIO(void);

void ToggleLED(void);

void main(void)
{
	unsigned char data; //register to hold letter sent and received
	unsigned int count; //counter for for loop
	
	Initialize(); //initialize IO, UART, SPI, set up nRF24L01 as TX

	while(1)
	{
		//check UART status register to see if data has been received.  if so, process
		while(DataRdyUSART())
		{
			data = ReadUSART(); //get data from UART
			nrf24l01_write_tx_payload(&data, 1, true); //transmit received char over RF

			//wait until the packet has been sent or the maximum number of retries has been reached
			while(!(nrf24l01_irq_pin_active() && nrf24l01_irq_tx_ds_active()));

			nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01
			nrf24l01_set_as_rx(true); //change the device to an RX to get the character back from the other 24L01

			//wait a while to see if we get the data back (change the loop maximum and the lower if
			//  argument (should be loop maximum - 1) to lengthen or shorten this time frame
			for(count = 0; count < 5000; count++)
			{
				//check to see if the data has been received.  if so, get the data and exit the loop.
				//  if the loop is at its last count, assume the packet has been lost and set the data
				//  to go to the UART to "?".  If neither of these is true, keep looping.
				if((nrf24l01_irq_pin_active() && nrf24l01_irq_rx_dr_active()))
				{
					nrf24l01_read_rx_payload(&data, 1); //get the payload into data
					break;
				}
				
				//if loop is on its last iteration, assume packet has been lost.
				if(count == 4999)
					data = '?';
			}
			
			nrf24l01_irq_clear_all(); //clear interrupts again
			printf("%c", data); //print the received data (or ? if none) to the screen
		
			DelayUS(130); //wait for receiver to come from standby to RX
			nrf24l01_set_as_tx(); //resume normal operation as a TX
											
			ToggleLED(); //toggle the on-board LED as visual indication that the loop has completed
		}
	}
}

void Initialize(void)
{
	InitializeIO();
	OpenUSART (USART_TX_INT_OFF & USART_RX_INT_OFF & USART_ASYNCH_MODE & USART_EIGHT_BIT & USART_CONT_RX & USART_BRGH_LOW, 64);
	OpenSPI(SPI_FOSC_16, MODE_00, SMPMID);
	nrf24l01_initialize_debug(false, 1, false);
}

void InitializeIO(void)
{
	ADCON1 = 0x7;
	TRISAbits.TRISA0 = 0;
	PORTAbits.RA0 = 1;
	
	TRISBbits.TRISB0 = 0;
	
	TRISC = 0x91;
	PORTC = 0x04;
}	

void ToggleLED(void)
{
	PORTAbits.RA0 = ~PORTAbits.RA0;
}

RX main:

#include <p18f452.h>
#include <stdio.h>
#include <usart.h>
#include <spi.h>
#include "delays.h"
#include "nrf24l01.h"

void Initialize(void);
void InitializeIO(void);

void ToggleLED(void);

void main(void)
{
	unsigned char data; //register to hold letter received and sent
	
	Initialize(); //initialize PLL, IO, SPI, set up nRF24L01 as RX

	//main program loop
	while(1)
	{
		//wait until a packet has been received
		while(!(nrf24l01_irq_pin_active() && nrf24l01_irq_rx_dr_active()));
		
		nrf24l01_read_rx_payload(&data, 1); //read the packet into data
		nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01
		
		DelayUS(130); //wait for the other 24L01 to come from standby to RX
		
		nrf24l01_set_as_tx(); //change the device to a TX to send back from the other 24L01
		nrf24l01_write_tx_payload(&data, 1, true); //transmit received char over RF
		
		//wait until the packet has been sent
		while(!(nrf24l01_irq_pin_active() && nrf24l01_irq_tx_ds_active()));

		nrf24l01_irq_clear_all(); //clear interrupts again
		nrf24l01_set_as_rx(true); //resume normal operation as an RX

		ToggleLED(); //toggle the on-board LED as visual indication that the loop has completed
	}
}

void Initialize(void)
{
	InitializeIO();
	OpenUSART (USART_TX_INT_OFF & USART_RX_INT_OFF & USART_ASYNCH_MODE & USART_EIGHT_BIT & USART_CONT_RX & USART_BRGH_LOW, 64);
	OpenSPI(SPI_FOSC_16, MODE_00, SMPMID);
	nrf24l01_initialize_debug(true, 1, false);
}

void InitializeIO(void)
{
	ADCON1 = 0x7;
	TRISAbits.TRISA0 = 0;
	PORTAbits.RA0 = 1;
	
	TRISBbits.TRISB0 = 0;
	
	TRISC = 0x91;
	PORTC = 0x04;
}	

void ToggleLED(void)
{
	PORTAbits.RA0 = ~PORTAbits.RA0;
}