nRF24L01 using PIC18F2550 with Brennen lib

Hello,

I manage to get Brennen’s library working with 2 PIC18LF2550 and nRF24L01+ modules. The compiler is C18.

The first problem I am facing with C18 is that I must use software UART with SPI as HW UART uses one pin that IS used for spi:

http://circuits.datasheetdir.com/19/PIC … pinout.jpg

As you can see pin 18 is both for RX and SDO.

Here is the HW configuration

CSN → A5

CE → A2

IRQ → C2

SCK → B1

SDI → B0

SDO → C7

LED0 → A0

LED1 → A1

I changed RX and TX pin from readuart.asm, writeuart.asm and openuart.asm from C:\Program Files (x86)\Microchip\mplabc18\v3.41\src\pmc_common\SW_UART

like this :

SWTXD           equ     PORTC           ; Transmit pin port and pin
SWTXDpin        equ     6
TRIS_SWTXD      equ     TRISC           ; Transmit pin tris and pin
SWRXD           equ     PORTC           ; Receive pin port and pin
SWRXDpin        equ     5
TRIS_SWRXD      equ     TRISC           ; Receive pin tris and pin

so that My UART TX and RX will be on pin C6 and C5.

Now I am not sure about how to configure uart in my main file. I changed “#include <usart.h>” in “#include <sw_uart.h>” here it is :

#include <p18F2550.H>
//#include <STDLIB.H> 
#include <stdio.h>
#include <sw_uart.h>
#include <spi.h>
#include "delays.h"
#include "nrf24l01.h"

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

void Initialize(void)
{
	InitializeIO(); //set up IO (directions and functions)
//	OpenUSART (USART_TX_INT_OFF & USART_RX_INT_OFF & USART_ASYNCH_MODE & USART_EIGHT_BIT & USART_CONT_RX & USART_BRGH_HIGH, 51); //open UART with spbrg = 8Mhz/(16*9600)-1
	OpenUART();
	OpenSPI(SPI_FOSC_16, MODE_00, SMPMID); //open SPI1
	nrf24l01_initialize_debug(false, 1, false); //initialize the 24L01 to the debug configuration as TX, 1 data byte, and auto-ack disabled
}
//initialize IO pins
void InitializeIO(void)
{
	ADCON1 = 0x7; //disable AD converter functionality on PORTA
	TRISAbits.TRISA0 = 0; //make PORTA.0 an output to control LED
	PORTAbits.RA0 = 1; //turn on LED0
	TRISAbits.TRISA1 = 0; //make PORTA.1 an output to control LED
	PORTAbits.RA1 = 1; //turn on LED1

	TRISCbits.TRISC2 = 1; //make sure that PORTC.2 INPUT since it is IRQ pin
	TRISAbits.TRISA2 = 0; //make sure that PORTA.2 OUTPUT since it is CE pin
	TRISCbits.TRISC7 = 0; //make sure that PORTC.7 OUTPUT since it is SDO pin
	TRISCbits.TRISC6 = 0; //make sure that PORTC.6 OUTPUT since it is TX pin UART
	TRISCbits.TRISC5 = 1; //make sure that PORTC.5 INPUT since it is RX pin UART
	TRISAbits.TRISA5 = 0; //make sure that PORT5.5 OUTPUT since it is CSN pin
	PORTAbits.RA5 = 1; //set CSN bit

	TRISBbits.TRISB1 = 0; //make sure that PORTB.1 OUTPUT since it is SCK pin

	TRISBbits.TRISB0 = 1; //make sure that PORTB.0 INPUT since it is SDI pin	
	//TRISC = 0x91; //make CSN, CE, SCK, MOSI (SDO), and TX outputs
}	

void main (void){

	unsigned char data; //register to hold letter sent and received
	unsigned int count; //counter for for loop

   while(1){

		//data = ReadUSART(); //get data from UART
		data=ReadUART(); //for software UART
		//delay_us(100);
		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 < 20000; 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 == 19999)
				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			
   }
}

This is only the Master’s code, I haven’t done the slave one yet. Should I include “uart0.c” ?

I have one error when I compile :

Error - could not find definition of symbol ‘DelayRXHalfBitUART’ in file ‘openuart.O’

I did a research in my files and there is no "DelayRXHalfBitUART".. Do you see anything wrong in my code, do you have any idea ?

Thank you

The DelayRXHalfBitUART() function may be extern’ed in sw_uart.h (or some similar file) that lives within Microchip’s C18 source libraries. You should be able to search the C18 source code for that symbol, and at least find a prototype for it, and maybe a description. The reason they may have done this would be to force you to write the delay function so they didn’t have to worry about all of the timing stuff that is required for a software UART. Doing it this way, you have to provide the implementation of that function yourself, but keep the function signature (function name, return type, and parameters) the same as what the SW UART library expects.

thank you for your reply Brennen,

I have decided to chose another PIC to be able to use HW Usart and HW SPI at the same time without bothering about changing pin configuration.

Now I am just facing one building error :

Error - could not find definition of symbol ‘nrf24l01_initialize_debug’ in file ‘./main.o’.

I can’t figure out why…

here is my main:

#include <p18F2620.H>
//#include <STDLIB.H> 
#include <stdio.h>
#include <usart.h>
#include <spi.h>
#include "delays.h"
#include "nrf24l01.h"

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

void Initialize(void)
{
	InitializeIO(); //set up IO (directions and functions)
	OpenUSART (USART_TX_INT_OFF & USART_RX_INT_OFF & USART_ASYNCH_MODE & USART_EIGHT_BIT & USART_CONT_RX & USART_BRGH_HIGH, 51); //open UART with spbrg = 8Mhz/(16*9600)-1
	OpenSPI(SPI_FOSC_16, MODE_00, SMPMID); //open SPI1
	nrf24l01_initialize_debug(false, 1, false); //initialize the 24L01 to the debug configuration as TX, 1 data byte, and auto-ack disabled
}
//initialize IO pins
void InitializeIO(void)
{
	ADCON1 = 0x7; //disable AD converter functionality on PORTA
	TRISAbits.TRISA0 = 0; //make PORTA.0 an output to control LED
	PORTAbits.RA0 = 1; //turn on LED0
	TRISAbits.TRISA1 = 0; //make PORTA.1 an output to control LED
	PORTAbits.RA1 = 1; //turn on LED1

	TRISBbits.TRISB7 = 1; //make sure that PORTB.7 INPUT since it is IRQ pin
	TRISBbits.TRISB6 = 0; //make sure that PORTB.6 OUTPUT since it is CSN pin
	TRISBbits.TRISB5 = 1; //make sure that PORTB.5 INPUT since it is CE pin
	PORTBbits.RB6 = 1; //set CSN bit

	TRISCbits.TRISC3 = 0; //make sure that PORTC.3 OUTPUT since it is SCK pin
	TRISCbits.TRISC4 = 1; //make sure that PORTC.4 INPUT since it is SDI pin
	TRISCbits.TRISC5 = 0; //make sure that PORTC.5 OUTPUT since it is SDO pin

	TRISCbits.TRISC6 = 0; //make sure that PORTC.6 OUTPUT since it is TX pin UART
	TRISCbits.TRISC7 = 1; //make sure that PORTC.7 INPUT since it is RX pin UART

	//TRISC = 0x91; //make CSN, CE, SCK, MOSI (SDO), and TX outputs
}	

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){

		data = ReadUSART(); //get data from UART
		//delay_us(100);
		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 < 20000; 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 == 19999)
				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			
   }
}

EDIT:

SOLVED this problem in incluing *.C as well as *.H, for instance, in the main :

#include "delays.h"
#include "delays.c"
#include "nrf24l01.h"
#include "nrf24l01.c"

and uart0.c and spi0.c in nrf24l01.h as well…

While doing that will work, it’s usually frowned-upon to #include source files (*.c). The problem you’re having is that you’re apparently not adding the source files to your project, so they’re not getting built by the compiler. If you do that, then you can remove the #includes.

Thank you Brennen for the explanation, you were right, now that I included *.c in the project it works well.

Now that I get it to build, I’m facing new problems…

I’ve adapted your code to mi PIC 18F2620 :

http://pinout-circuits-images.dz863.com … 8F2620.jpg

datasheet : http://ww1.microchip.com/downloads/en/d … 39626b.pdf

And I have added some printf to see where I am in the code. I’m only talking about the local/master, not the remote/slave.

Here is the code commented :

#include <p18F2620.H>
//#include <STDLIB.H> 
#include <stdio.h>
#include <usart.h>
#include <spi.h>
#include "delays.h"
#include "nrf24l01.h"

void Initialize(void);
void InitializeIO(void);
void ToggleLED(int id); //toggle the current state of the on-board LED
void CheckErrorsUSART(void); //fix any framing or overrun errors in the USART

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

	printf("OK \n\r"); //be sure That I'm running the programm

	while(1){
		CheckErrorsUSART();

		while(DataRdyUSART()){
			data = ReadUSART(); //get data from UART
			printf("merci\n\r");
			//delay_us(100);
			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()));
			if (nrf24l01_irq_tx_ds_active()){ //see if it was sent or not and tell me..
				printf("Sent\n\r");
			} else {
				printf("Something's wrong\n\r");
			}
			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 < 20000; 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 (count%1000==0) //tell me that I'm waiting..
					printf("count:%d \n\r",count);

				//if loop is on its last iteration, assume packet has been lost.
				if(count == 19999)
					data = '?';
			}
			
			nrf24l01_irq_clear_all(); //clear interrupts again
			printf("data: %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(1); //toggle the on-board LED as visual indication that the loop has completed		
	   }
	}
}

//initialize IO pins
void InitializeIO(void)
{
	ADCON1 = 0x0F; //disable AD converter functionality on PORTA
	CMCON = 0x07; //disable comparators on PORTA

	TRISAbits.TRISA0 = 0; //make PORTA.0 an output to control LED
	PORTAbits.RA0 = 1; //turn on LED0
	TRISAbits.TRISA1 = 0; //make PORTA.1 an output to control LED
	PORTAbits.RA1 = 1; //turn on LED1

	TRISBbits.TRISB7 = 1; //make sure that PORTB.7 INPUT since it is IRQ pin
	TRISBbits.TRISB6 = 0; //make sure that PORTB.6 OUTPUT since it is CSN pin
	TRISBbits.TRISB5 = 1; //make sure that PORTB.5 INPUT since it is CE pin
	PORTBbits.RB6 = 1; //set CSN bit

	TRISCbits.TRISC3 = 0; //make sure that PORTC.3 OUTPUT since it is SCK pin
	TRISCbits.TRISC4 = 1; //make sure that PORTC.4 INPUT since it is SDI pin
	TRISCbits.TRISC5 = 0; //make sure that PORTC.5 OUTPUT since it is SDO pin

	TRISCbits.TRISC6 = 0; //make sure that PORTC.6 OUTPUT since it is TX pin UART
	TRISCbits.TRISC7 = 1; //make sure that PORTC.7 INPUT since it is RX pin UART

	//TRISC = 0x91; //make CSN, CE, SCK, MOSI (SDO), and TX outputs
}	

void Initialize(void)
{
	InitializeIO(); //set up IO (directions and functions)
	OpenUSART (USART_TX_INT_OFF & USART_RX_INT_OFF & USART_ASYNCH_MODE & USART_EIGHT_BIT & USART_CONT_RX & USART_BRGH_HIGH, 51); //open UART with spbrg = 8Mhz/(16*9600)-1
	OpenSPI(SPI_FOSC_16, MODE_00, SMPMID); //open SPI1
	nrf24l01_initialize_debug(false, 1, false); //initialize the 24L01 to the debug configuration as TX, 1 data byte, and auto-ack disabled
}

void ToggleLED(int id) 
{ 
	if (id==1)
   	PORTAbits.RA1 = ~PORTAbits.RA1;
	else 
	PORTAbits.RA0 = ~PORTAbits.RA0;
} 

void CheckErrorsUSART(void)
{
	unsigned char data; //dummy data variable
	
	//check for overrun error
	if(RCSTAbits.OERR)
	{
		RCSTAbits.CREN = 0; //clearing CREN clears OERR
		RCSTAbits.CREN = 1; //re-establish communications
		data = ReadUSART(); //make a dummy read in case there is data in the USART
	}
	 
	//check for framing error  
	if(RCSTAbits.FERR)
		data = ReadUSART(); //reading the USART clears this error
}

Here is how I connected the PIC to the nRF24L01+ module :

CSN (RB6) to CSN

CE (RB5) to CE

IRQ (RB7) to IRQ

SCK (RC3 default) to SCK

SDI (RC4 default) to MISO

SDO (RC5 default) to MOSI

LED0 (RA0)

LED1 (RA1)

Now here is what I get on the terminal :

OK a //<-- I did press “a” on the keyboard

OK

merci

So the program doesn’t obviously send anything, and the most surprising thing is that it DOES go out of the “while(1)” loop to print “OK”…

I have no idea how this is possible… I must do something wrong while initializing the pins don’t I don’t know where… The datasheet isn’t that complex…

------EDIT

Here is my the bit configuration file:

#define nrf24l01_CE_IOREGISTER      PORTB // B5 100 000
#define nrf24l01_CE_PINMASK         0x20

//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      PORTB // B6 1 000 000
#define nrf24l01_CSN_PINMASK      0x40

//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 //B7 10 000 000
#define nrf24l01_IRQ_PINMASK      0x80

I will say that one error I can see is that you are setting CE as an input, and it should be an output. Also, based on the code above, I would assume that you would have seen either “Sent” or “Something’s wrong” in the serial log, and you didn’t post either of those in your snippet. It looks like your definitions in nrf24l01.h are correct based on the pins you say are connected.

Thank you for your reply. About the CE, I wasn’t sure because in the pdf tutorial you have written that CE should be an Input ! I’ll give it a try. As I said, there is no log such as “sent” or “something’s wrong”… finally, I might have a problem in my configuration bits with the oscillator as I want to use an external 8Mhz crystal…

If you are actually seeing data come across the UART and into your computer, then chances are your oscillator is set up OK, as UARTs tend to have fairly tight timing restrictions.

One other thing that is helpful is to do a full nRF24L01 register dump to the UART. You can use the nrf24l01_get_all_registers() function to get the values (pass in a char array of [I think] 35 elements) and then print the values out in a loop.

Hello, I’ve been working on the module quite a long time this week and I faced a lot of troubles dealing with the configuration bits.

Here is what I have (it works almost the way it should…) :

#pragma config OSC = HS//
//#pragma config FCMEN = OFF //Fail-Safe Clock Monitor disabled
//#pragma config IESO = OFF //Oscillator Switchover mode disabled
#pragma config PWRT = ON //Power-up Timer Enable
//#pragma config BOREN = OFF //Brown-out Reset disabled in hardware and software 
//#pragma config BORV = 0 //Brown Out Reset Voltage: Maximum setting
#pragma config WDT = OFF //
//#pragma config WDTPS = 1 //Watchdog Timer Postscale Select 1:1
//#pragma config CCP2MX = PORTC //CCP2 input/output is multiplexed with RC1 
//#pragma config PBADEN = OFF // PORTB<4:0> pins are configured as digital I/O on Reset 
//#pragma config LPT1OSC = OFF //Timer1 configured for higher power operation
#pragma config MCLRE = ON //(ON)MCLR pin enabled; RE3 input pin disabled
#pragma config STVREN = ON //Stack full/underflow will not cause Reset 
#pragma config LVP = OFF //Single-Supply ICSP disabled 
//#pragma config XINST = OFF //Instruction set extension and Indexed Addressing mode disabled (Legacy mode)
//#pragma config DEBUG = OFF //

i have implemented the " nrf24l01_get_all_registers" function like this :

	for (i=0;i<35;i++){
		printf("%d: %s",i,verif[i]);
		delay_us(100);	
	}

but the output is either blank or gibberish :

0: 1: 2: 3: 4: 5: 6: !7: 9 !8:9: 10: 11: 12: 13: 14: 15: 0F€ñ¨ŽÍªÐ

ÀlY4°16: 0F€ñ¨ŽÍªÐ

ÀlY4°17: 0F€ñ¨ŽÍªÐ

ÀlY4°18: 0F€ñ¨ŽÍªÐ

ÀlY4°19: 0F€ñ¨ŽÍªÐ

ÀlY4°20: F€ñ¨ŽÍªÐ

ÀlY4°21: €ñ¨ŽÍªÐ

ÀlY4°22: ñ¨ŽÍªÐ

ÀlY4°23: ¨ŽÍªÐ

ÀlY4°24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34:

Here is my full code, and the output :

#include <p18F2620.H>
//#include <STDLIB.H> 
#include <stdio.h>
#include <usart.h>
#include <spi.h>
#include "delays.h"
#include "nrf24l01.h"


#pragma config OSC = HS//
//#pragma config FCMEN = OFF //Fail-Safe Clock Monitor disabled
//#pragma config IESO = OFF //Oscillator Switchover mode disabled
#pragma config PWRT = ON //Power-up Timer Enable
//#pragma config BOREN = OFF //Brown-out Reset disabled in hardware and software 
//#pragma config BORV = 0 //Brown Out Reset Voltage: Maximum setting
#pragma config WDT = OFF //
//#pragma config WDTPS = 1 //Watchdog Timer Postscale Select 1:1
//#pragma config CCP2MX = PORTC //CCP2 input/output is multiplexed with RC1 
//#pragma config PBADEN = OFF // PORTB<4:0> pins are configured as digital I/O on Reset 
//#pragma config LPT1OSC = OFF //Timer1 configured for higher power operation
#pragma config MCLRE = ON //(ON)MCLR pin enabled; RE3 input pin disabled
#pragma config STVREN = ON //Stack full/underflow will not cause Reset 
#pragma config LVP = OFF //Single-Supply ICSP disabled 
//#pragma config XINST = OFF //Instruction set extension and Indexed Addressing mode disabled (Legacy mode)
//#pragma config DEBUG = OFF // 

void Initialize(void);
void InitializeIO(void);
void ToggleLED(int id); //toggle the current state of the on-board LED
void CheckErrorsUSART(void); //fix any framing or overrun errors in the USART
unsigned char verif[35];
int i=0;
int compteur=0;

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

	nrf24l01_get_all_registers(verif);
	for (i=0;i<35;i++){
		printf("%d: %s",i,verif[i]);
		delay_us(100);	
	}

	while(1){
	delay_us(10000);
	printf("\n\r wait");
	ToggleLED(1);
	CheckErrorsUSART();
	
	//check UART status register to see if data has been received.  if so, process
	while(DataRdyUSART()){
			data = ReadUSART(); //get data from UART
			printf("\n merci");
			//delay_us(100);
			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()));
			if (nrf24l01_irq_tx_ds_active()){ //see if it was sent or not and tell me..
				printf("\n Sent");
			} else {
				printf("\n Something's wrong");
			}
			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 < 20000; 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 (count%1000==0) //tell me that I'm waiting..
					printf("\n count:%d",count);

				//if loop is on its last iteration, assume packet has been lost.
				if(count == 19999)
					data = '?';
			}
			
			nrf24l01_irq_clear_all(); //clear interrupts again
			printf("data: %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(2); //toggle the on-board LED as visual indication that the loop has completed		
	   }
	}
}



//initialize IO pins
void InitializeIO(void)
{	
	ADCON1 = 0x0F; //disable AD converter functionality on PORTA
	CMCON = 0x07; //disable comparators on PORTA

	TRISAbits.TRISA0 = 0; //make PORTA.0 an output to control LED
	PORTAbits.RA0 = 1; //turn on LED0
	TRISAbits.TRISA1 = 0; //make PORTA.1 an output to control LED
	PORTAbits.RA1 = 1; //turn on LED1

	TRISBbits.TRISB7 = 1; //make sure that PORTB.7 INPUT since it is IRQ pin
	TRISBbits.TRISB6 = 0; //make sure that PORTB.6 OUTPUT since it is CSN pin
	TRISBbits.TRISB5 = 0; //make sure that PORTB.5 OUTPUT since it is CE pin
	PORTBbits.RB6 = 1; //set CSN bit

	TRISCbits.TRISC3 = 0; //make sure that PORTC.3 OUTPUT since it is SCK pin
	TRISCbits.TRISC4 = 1; //make sure that PORTC.4 INPUT since it is SDI pin
	TRISCbits.TRISC5 = 0; //make sure that PORTC.5 OUTPUT since it is SDO pin

	TRISCbits.TRISC6 = 0; //make sure that PORTC.6 OUTPUT since it is TX pin UART
	TRISCbits.TRISC7 = 1; //make sure that PORTC.7 INPUT since it is RX pin UART

	//TRISC = 0x91; //make CSN, CE, SCK, MOSI (SDO), and TX outputs
}	

void Initialize(void)
{
	InitializeIO(); //set up IO (directions and functions)
	OpenUSART (USART_TX_INT_OFF & USART_RX_INT_OFF & USART_ASYNCH_MODE & USART_EIGHT_BIT & USART_CONT_RX & USART_BRGH_HIGH, 51); //open UART with spbrg = 8Mhz/(16*9600)-1
	OpenSPI(SPI_FOSC_16, MODE_00, SMPMID); //open SPI1
	nrf24l01_initialize_debug(false, 1, false); //initialize the 24L01 to the debug configuration as TX, 1 data byte, and auto-ack disabled
	printf("\n\r Init OK");
}

void ToggleLED(int id) 
{ 
	if (id==1)
   	PORTAbits.RA1 = ~PORTAbits.RA1;
	else 
	PORTAbits.RA0 = ~PORTAbits.RA0;
} 

void CheckErrorsUSART(void)
{
	unsigned char data; //dummy data variable
	
	//check for overrun error
	if(RCSTAbits.OERR)
	{
		RCSTAbits.CREN = 0; //clearing CREN clears OERR
		RCSTAbits.CREN = 1; //re-establish communications
		data = ReadUSART(); //make a dummy read in case there is data in the USART
	}
	 
	//check for framing error  
	if(RCSTAbits.FERR)
		data = ReadUSART(); //reading the USART clears this error
}

–OUTPUT:

Init OK0: 1: 2: 3: 4: 5: 6: 1P‰227: 9 1P‰228:9: 10: 11: 12: 13: 14: 15: 0F€±¨ŽÍªÐ16: 0F€±¨ŽÍªÐ17: 0F€±¨ŽÍªÐ18: 0F€±¨ŽÍªÐ19: 0F€±¨ŽÍªÐ20: F€±¨ŽÍªÐ21: €±¨ŽÍªÐ22: ±¨ŽÍªÐ23: ¨ŽÍªÐ24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34:

wait

wait

wait

wait

wait

wait

wait

wait

wait

wait

wait

wait

wait<------------------ I type a character

merci

Sent

count:0

count:1000

count:2000

count:3000

count:4000

count:5000

count:6000

count:7000

count:8000

count:9000

count:10000

count:11000

count:12000

count:13000

count:14000

count:15000

count:16000

count:17000

count:18000

count:19000data: ?

wait

wait

wait

I managed to understand every configuration bit, and I try now to get the Receiver receive and transmit again. I am using the exact same code as Brennen in his tutorial. I guess there is something wrong with my communication as I can’t even read properly the module’s registers… but the SPI seems all right.

I am using a lot a wires around the modules, and both RX and TX are powered by the same power supply (the 2 PICS and 2 modules are very close to each other 10cm or so), and finally there are quite a lot of wires and wifi connections around, do you think this could be a major problem ?

edit: Brennen, didn’t you bother about the configuration bits ? You don’t mention them in your tutorials

SPI isn’t working if you can’t read the registers. You need to get it working, first.

I don’t see what I could change to brennen’s spi0 function, it couldn’t be more simple :

spi0.c :

#include <spi.h>
#include <p18f2620.h>

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

or my initialization is wrong ```
OpenSPI(SPI_FOSC_16, MODE_00, SMPMID); //open SPI1


I'm not sure about the "SPI_FOSC_16" and the SMPMID...

otherwise, it could be my CE,IRQ or CSN but I'm quite sure that this is all right.. it couldn't be from something else right ?

You must have something wrong if you can’t read the registers. Tthe first thing I did when I was working on my software was to check that I could read them:

/*
** test.c
** SPI test program for PIC18F24J11 and nRF24L01 or nRF24L01+
** Checks SPI comms between PIC and wireless chip
** LED on RC0
** 
*/

#include <p18cxxx.h>
#include <spi.h>

//function prototypes
unsigned char spi_Send_Read(unsigned char);
void dly(void);

// Defines
#define SPI_SCK		LATCbits.LATC3		// Clock pin, PORTC pin 3 
#define SPI_SO		LATCbits.LATC5		// Serial output pin, PORTC pin 5 
#define SPI_SI		PORTCbits.RC4		// Serial input pin, PORTC pin 4 
#define SPI_CSN		LATCbits.LATC2		// CSN output pin, PORTC pin 2
#define SPI_CE		LATCbits.LATC1		// CE output pin, PORTC pin 1
#define SPI_IRQ		PORTBbits.RB0		// IRQ input pin, PORTB pin 0
#define SPI_SCALE	4              		// postscaling of signal 

// Macros
#define nop() _asm nop _endasm

void main(void)
{
	unsigned char status = 0;
	unsigned char data[5];
	int i;

	// run internal oscillator at 8 MHz
	OSCCON = OSCCON | 0b01110000;
	while (!OSCCONbits.OSTS)	// wait for OSTS to go high
		;

	

	OpenSPI(SPI_FOSC_16, MODE_00, SMPMID); //open SPI1
	TRISCbits.TRISC3 = 0;	// SDO output
	TRISCbits.TRISC5 = 0;   // SCK output
	TRISCbits.TRISC2 = 0;	// CSN output
	TRISCbits.TRISC1 = 0;	// CE output
	SPI_CSN = 1;		// CSN high
	SPI_SCK = 0;		// SCK low
	SPI_CE	= 0;		// CE low
	TRISCbits.TRISC0 = 0; // RC0 (LED) output
	nop();

	//write TX_ADDRESS register
	SPI_CSN = 0;			//CSN low
	status = spi_Send_Read(0x30);
	spi_Send_Read(0x11);
	spi_Send_Read(0x22);
	spi_Send_Read(0x33);
	spi_Send_Read(0x44);
	spi_Send_Read(0x55);
	SPI_CSN = 1;			//CSN high

	for (i = 0; i < 5; i++)
		data[i] = 0;

	LATCbits.LATC0 = 1;		//LED on


	//read TX_ADDRESS register
	//Check that values are correct using the MPLAB debugger
	SPI_CSN = 0;			//CSN low
	status = spi_Send_Read(0x10);
	data[0] = spi_Send_Read(0x00);	// 0x11
	data[1] = spi_Send_Read(0x00);	// 0x22
	data[2] = spi_Send_Read(0x00);	// 0x33
	data[3] = spi_Send_Read(0x00);	// 0x44
	data[4] = spi_Send_Read(0x00);	// 0x55
	SPI_CSN = 1;					// CSN high

	while (1)
		;
}


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

Thank’s a lot for this example, I’ll give it a try tomorrow to see what’s wrong with my SPI

Can you tell me what is the nop() function made for ?

EDIT:

When you say

//Check that values are correct using the MPLAB debugger

I guess you can do this because of your programmer, I’m not sure to be able to read this easily with a pickit3, am I right ? (anyway I will print it in a terminal using Uart)

The nop() function was in case I needed some short delays. You should be able to remove it.

I used an ICD 3 for debugging, the PICkit 3 will work just as well.

Ok thank you very much for your time, it helps me a lot, I have to know better my tools, I have never used it for debugging yet.

One last thing about the code you gave (I can’t test it before tomorrow but I’d like to understand everything)

you have first :

   //write TX_ADDRESS register
   SPI_CSN = 0;         //CSN low
   status = spi_Send_Read(0x30);

and secondly :

//read TX_ADDRESS register
   //Check that values are correct using the MPLAB debugger
   SPI_CSN = 0;         //CSN low
   status = spi_Send_Read(0x10);

for the second, I agree that “0x10” is the TX_ADDR, (according to the [datasheet) but what about the “0x30” in the first snippet… shouldn’t it be RX_ADDR ?

edit:

Ok I got it, the first means that you want to write 001A AAAA on register 1 0000 which is TX_ADDR and then you simply want to read 000A AAAA that same register…

Thank you again for your help](Explore our product portfolio - nordicsemi.com)

hmm interresting… I got the SPI working, I guess this is due to MCLRE pull up resistor, as it’s the only thing I changed and I am able to read registers now, here is how it looks like :

0: 52
1: a1
2: f
3: 0
4: 1
5: 2a
6: c0
7: 0
8: 1d
9: 0
a: 31
b: 80
c: 10
d: a
e: 2a
f: c1
10: 8
11: 8a
12: 0
13: 26
14: 2
15: 90
16: 4c
17: 14
18: c
19: a0
1a: 5
1b: 68
1c: 86
1d: 2a
1e: a0
1f: 42
20: 33
21: 20
22: 10
23: 22

I’ll try to guess what could be wrong, if you see anything… Thank you very much for your help

They seem to be completely wrong. What do you get if you write to them?

I have added a part of your code simply to write something in TX buffer:

	Initialize(); //initialize IO, UART, SPI, set up nRF24L01 as TX
	nrf24l01_flush_tx();
	nrf24l01_flush_rx();
	nrf24l01_get_all_registers(buffer);
   for(count = 0; count < 36; count++)
       printf("%x: %x\r\n", count, buffer[count]); 
//ADDED---------------------------------------------------------
	status = spi1_send_read_byte(0x30);
	spi1_send_read_byte(0x11);
	spi1_send_read_byte(0x22);
	spi1_send_read_byte(0x33);
	spi1_send_read_byte(0x44);
	spi1_send_read_byte(0x55);
	
	printf("WRITING...\n\r");
   nrf24l01_get_all_registers(buffer);
	for(count = 0; count < 36; count++)
       printf("%x: %x\r\n", count, buffer[count]); 
//---------------------------------------------------------

OUTPUT:

Init OK0: a

1: 0

2: 3

3: 3

4: 3

5: 2

6: f

7: e

8: 0

9: 0

a: e7

b: e7

c: e7

d: e7

e: e7

f: c2

10: c2

11: c2

12: c2

13: c2

14: c3

15: c4

16: c5

17: c6

18: e7

19: e7

1a: e7

1b: e7

1c: e7

1d: 1

1e: 0

1f: 0

20: 0

21: 0

22: 0

23: 11

WRITING…

0: a

1: 0

2: 3

3: 3

4: 3

5: 2

6: f

7: e

8: 0

9: 0

a: e7

b: e7

c: e7

d: e7

e: e7

f: c2

10: c2

11: c2

12: c2

13: c2

14: c3

15: c4

16: c5

17: c6

18: e7

19: e7

1a: e7

1b: e7

1c: e7

1d: 1

1e: 0

1f: 0

20: 0

21: 0

22: 0

23: 11

I’m not sure about the test I just made… maybe they look better now !?

I don’t think that you are accessing the registers properly. See table 20 in the data sheet.