nRF24L01 timing issues

Hey brennen and mchang,

Thanks for the information you have posted here. I’m going to be using the 24L01 with a PIC (won’t use C but looking at your C has helped a lot!).

I have read and reread your conversations and I was hoping you guys could respond to this to clear up a few things:

  1. Did you guys finally decide (and perhaps test) that it is NOT necessary to flush the RX buffers if you de-assert CE before reading the RX buffers?

  2. You both mention flushing SPI buffers. Is this something related to the host processor that must be done before using the SPI interface?

  3. Do you guys query the RX_PW_P registers first to obtain the length (number of bytes) to read from the RX Buffer? If not, how do you know how many bytes are valid in the RX buffer?

  4. Brennen, your code mentions “len…should be sized according to the payload length specified to the nrf24l01” for nrf24l01_write_tx_payload. Does this require some additional setup of the nrf24L01 before sending the data or does it just mean however much data you write to the TX buffers before triggering a transmission will be sent?

  5. You guys have any input regarding reliability of transmission? Is 1mbit/sec more reliable than 2mbit/sec? Unfortunately I want to send from one transmitter to many receivers so won’t be using Auto-Ack or any other 2-way protocol.

Thanks, Dan

  1. I didn’t test this personally. The code I used that worked for me is what I have posted. mchang will answer this question better than me.

  2. If you don’t flush your SPI buffers on your microcontroller and they get full, new information is simply dropped as it comes in (at least this is how it is with the LPC2148 that I did development with).

  3. The RX_PW_P registers that you refer to simply set the payload lengths that I described in 4 below. To read the first RX payload, you must use the R_RX_PAYLOAD instruction and clock out the number of bytes in your payload (then bring CSN high again).

If there are additional payloads in the RX FIFO, honestly I’m not sure the best way to handle that. I would assume that you would read the FIFO_STATUS register and look at the RX_EMPTY bit. If the bit is 0, then you still have stuff in the FIFO, and you should continue to use the R_RX_PAYLOAD instruction to clock out payloads. You should probably bring the CSN pin high between each payload, otherwise the RX_EMPTY bit may not set as it should. This is all theoretical as I’ve yet to test getting more than one payload at a time. Mchang may know more.

  1. You should always set up your TX payload length before you start sending or receiving packets. This is what I am referring to in what you quoted of me. This simply means that len should be between 1 and 32, since that is what the nRF24L01 allows. Remember that these payload lenghts are set per pipe, so you may have different lengths per pipe depending on your application.

  2. I never actually tried 1 Mbps, but 2 Mbps is very reliable from close distances. I am using the MiRF-v2 boards with the chip antenna, so they don’t have the best range ever, but they definitely work. I still haven’t built a real application to test the distances of these chips, so I can’t comment too much on their distance to data reliabliity relationship. Everything I’ve done has been from about a foot apart for testing purposes.

Thanks again Brennen! I think I had a HUGE misunderstanding of how the part works.

Just to be sure, you must configure it apriori for a fixed payload size? You do this by setting the PRX part RX_PW_P register to the expected payload size. Otherwise the part ignores payloads of different sizes? Then you only load that many bytes into the PTX part FIFO?

If this is true then the part isn’t designed to deal with variable length payloads?

Thanks again, Dan

Correct, sort of. You indeed must configure the RX_PW_P registers a priori, but only on a per packet basis. Theoretically, every packet you transmit could be of different sizes (you’d still have to change the TX payload size per packet on the transmitter), but the receiver is always expecting a certain size. This could potentially be overcome by writing in some protocol, but the 24L01s always look for a certain size of packet on the receiving end. Well, at least that’s what I got out of the datasheet. :lol:

Granted, however, there are 6 pipes on these puppies, each of which can have a different payload size. Therefore, you could have 6 different message sizes being received “simulatneously” and never have to change anything (until you tried to send though, since you only have one transmitter and you’d have to change the payload width per packet in the worst case). I say “simulataneously” because you can only receive one packet at a time, regardless of how many pipes you have. The pipes only give you the flexibility of not having to change settings constantly.

From the for-what-its-worth department, I got my code running. I am transmitting 2-byte packets in ShockBurst Mode. The sequence I use for reading information from the PRX part after getting an interrupt is:

  1. Read the payload out of the RX FIFO

  2. Clear pending interrupts (write 0x70 to STATUS)

I leave CE asserted all the time for the PRX part. I don’t have to flush the RX FIFO.

I get significantly fewer lost packets in 2 Mbps mode than in 1 Mpbs mode.

Let me know if you’d like to see the code. It’s for a PIC 16F873.

Hi djulio99,

I was wondering if you could still post your 16F873 code?

I’m using a 16F88 and just trying to mimick the example code I found on the sparkfun site, but I’m using a CCS compiler so - it’s different than the CCX5.

Basically I’m just trying to have a simple shockburst transmission/reception work for now. I can see my SPI interface output and clock to the nRF24L01 on the scope, the bit patterns and clocking seem correct, but my transmissions don’t seem to work. I should also note I’m pretty new to this stuff.

I tried posting my code on a previous reply, but the forum is blocking me?? usage words or something? don’t know why – I don’t use forums much so maybe I did something wrong.

So a question for anyone. I’m trying to use the SPI interface on the PIC - is there any issues with that? I notice a lot of code that does a bit banging interface. Is there possible timing discrepancies with SPI?

thanks

rschoele

Hi djulio99,

First off thanks everyone for sharing your knowledge. I’m pretty new at this.

djulio99 - I was wondering if you could post your code for the 16F873? I’m using a 16F88, using the SPI interface. I’ve tried re-writing example code to work with my set up - I can see my data clock into the nRF24L01 with an analyzer, but I think I either have timing issues or I’m missing something because I can’t get any comm going. I’m using a ccs picc compiler so it’s a bit different than the CCX5(?) code examples I’ve found.

Right now I’m just trying to mimick the example and have basic shockburst TX and receive a payload on the other end. Once I get basics working then I’ll work towards using the more advanced features.

here’s my TX and RX code - if anyone sees an issue please let me know. in the meantime I’ll keep grinding. thanks

TX code:

#include<16F88.h>

#fuses INTRC_IO,NOWDT,NOPUT,MCLR,NOPROTECT,NOBROWNOUT,NOLVP,NOFCMEN,NOIESO
#use delay(clock=4000000)
#use standard_io(A)
#use standard_io(B)

/********************************START PIC16F88 Defines***********************************************/

// Control and SPI Pin defines ////////////////////////////////////////
#define CE		PIN_B5		// output Chip enable to nRF24L01 CE PIN_1
#define CSN		PIN_B3		// output Chip Select to nRF24L01 CSN PIN_2
#define SCK		PIN_B4		// serial clock output to nRF24L01 SCK PIN_3
#define MOSI	PIN_B2		// serial data out to nRF24L01 MOSI PIN_4 
#define MISO	PIN_B1		// serial data in from nRF24L01 MISO PIN_5
#define IRQ		PIN_B0		// input valid TX/RX from nRF24L01 IRQ PIN_6

// LED indicator Pins
#define LED0	PIN_A0
#define LED1	PIN_A1
#define LED2	PIN_A2

/********************************END PIC16F88 Defines*************************************************/
unsigned int cmd, data, j;

void spi_write1(int a){
		delay_us(10);
		spi_write(a);
		delay_us(10);
}

// Configure transmitter
void TX_Mode(){

output_low(CE);

output_low(CSN);
cmd = 0x20;	// write register, CONFIG
data = 0x38; //ptx, crc enable, mask a couple ints
	spi_write1(cmd);
	spi_write1(data);
output_high(CSN);
delay_us(20);

output_low(CSN);
cmd = 0x24; // write register, setup_retr
data = 0x00;	// setup_retr = off
	spi_write1(cmd);
	spi_write1(data);
output_high(CSN);
delay_us(20);

output_low(CSN);
cmd = 0x23; // write register, setup_aw
data = 0x03;	// address width = 5
	spi_write1(cmd);
	spi_write1(data);
output_high(CSN);
delay_us(20);

output_low(CSN);
cmd = 0x26; // write register, RF_SETUP
data = 0x0F;	// data rate =2Mbps,0dBm,LNA gain
	spi_write1(cmd);
	spi_write1(data);
output_high(CSN);
delay_us(20);

output_low(CSN);
cmd = 0x25; // write register, RF_CH
data = 0x02;	// default ch 2
	spi_write1(cmd);
	spi_write1(data);
output_high(CSN);
delay_us(20);

output_low(CSN);
cmd = 0x30; // write register, TX address
data = 0xE7;	// set address E7E7E7E7E7
	spi_write(cmd);
	for(j=0;j<5;j++){
		spi_write1(data);
	}
output_high(CSN);
delay_us(20);

output_low(CSN);
cmd = 0x21; // write register, en_aa
data = 0x00;	// disable auto-act in RX mode
	spi_write1(cmd);
	spi_write1(data);
output_high(CSN);
delay_us(20);
}

// Transmit data
void TX_Data(){

output_low(CSN);
cmd = 0x27; // write register, STATUS
data = 0x7E;	// clear previous ints
	spi_write1(cmd);
	spi_write1(data);
output_high(CSN);
delay_us(20);

output_low(CSN);
cmd = 0x20; // write register, CONFIG
data = 0x3A;	// power up = 1
	spi_write1(cmd);
	spi_write1(data);
output_high(CSN);
delay_us(20);

output_low(CSN);
cmd = 0xE1; // flush_tx
	spi_write1(cmd);
output_high(CSN);
delay_us(20);

output_low(CSN);
cmd = 0xA0; // write tx_payload
data = 0x34;	// 4 byte payload
	spi_write1(cmd);
	spi_write1(data);
data = 0x33;	// 4 byte payload
	spi_write1(data);
data = 0x32;	// 4 byte payload
	spi_write1(data);
data = 0x31;	// 4 byte payload
	spi_write1(data);
output_high(CSN);
delay_us(20);

output_high(CE);
delay_us(20);
output_low(CE);
}


/********************************TX/RX IRQ Interrupt Acknowledgement********************************/

//Main
void main(){
setup_oscillator(OSC_4MHZ|OSC_INTRC);
setup_adc_ports(NO_ANALOGS);	// Set PortA Digital IO
setup_adc(ADC_OFF);				// Turn off ADC
setup_ccp1(CCP_OFF);			// Turn off CCP - will disrupt output writes on PIN_B3 if on
setup_spi(SPI_MASTER|SPI_XMIT_L_TO_H|SPI_CLK_DIV_64);

// set up IRQ (PIN_B0) interrupt for TX/RX notification
//enable_interrupts(INT_EXT);
//ext_int_edge(H_TO_L);
//enable_interrupts(GLOBAL);
//output_low(CE);		// set CE low to disable transmission
output_b(0b00001000);
output_low(LED0 | LED1 | LED2);		// set LEDs Low

delay_ms(2);
output_high(LED0);
TX_Mode();
output_low(LED0);

	while(1){

		TX_Data();
		output_high(LED2);
		delay_ms(10);
		output_low(LED2);
		delay_ms(500);
	}

}

RX code

/* RF weapon track test code - R.Schoelerman 11/06
SPI interface between PIC16F88 and nRF24L01

nRF24L01 IO:
	Chip Select				RB3
	Chip Enable				RB5
	IRQ						RB6

SPI Control Pins:
	Serial Data Out (SDO)	RB2
	Serial Data In (SDI)	RB1
	Serial Clock (SCK)		RB4
*/
#include<16F88.h>

#fuses INTRC_IO,NOWDT,NOPUT,MCLR,NOPROTECT,NOBROWNOUT,NOLVP,NOFCMEN,NOIESO
#use delay(clock=4000000)
#use standard_io(A)
#use standard_io(B)

/********************************START PIC16F88 Defines***********************************************/

// Control and SPI Pin defines ////////////////////////////////////////
#define CE		PIN_B5		// output Chip enable to nRF24L01 CE PIN_1
#define CSN		PIN_B3		// output Chip Select to nRF24L01 CSN PIN_2
#define SCK		PIN_B4		// serial clock output to nRF24L01 SCK PIN_3
#define MOSI	PIN_B2		// serial data out to nRF24L01 MOSI PIN_4 
#define MISO	PIN_B1		// serial data in from nRF24L01 MISO PIN_5
#define IRQ		PIN_B0		// input valid TX/RX from nRF24L01 IRQ PIN_6

// LED indicator Pins
#define LED0	PIN_A0
#define LED1	PIN_A1
#define LED2	PIN_A2

/********************************END PIC16F88 Defines*************************************************/
unsigned int data, cmd, j;

void spi_write1(int a){
		delay_us(10);
		spi_write(a);
		delay_us(10);
}
void spi_read1(int a){
		delay_us(10);
		data = spi_read(a);
		delay_us(10);
}
// Configure receiver
void RX_Mode(void){
int data, cmd, j;

output_low(CE);

output_low(CSN);
cmd = 0x20;	// write register, CONFIG
data = 0x39; //prx, crc enable, mask a couple ints
	spi_write1(cmd);
	spi_write1(data);
output_high(CSN);
delay_us(20);

output_low(CSN);
cmd = 0x21; // write register, en_aa
data = 0x00;	// dissable auto ack
	spi_write1(cmd);
	spi_write1(data);
output_high(CSN);
delay_us(20);

output_low(CSN);
cmd = 0x23; // write register, setup_aw
data = 0x03;	// address width = 5
	spi_write1(cmd);
	spi_write1(data);
output_high(CSN);
delay_us(20);

output_low(CSN);
cmd = 0x26; // write register, RF_SETUP
data = 0x0F;	// data rate =2Mbps,0dBm,LNA gain
	spi_write1(cmd);
	spi_write1(data);
output_high(CSN);
delay_us(20);

output_low(CSN);
cmd = 0x31; // write register, tx address
data = 0x04;	// 4 byte payload
	spi_write1(cmd);
	spi_write1(data);
output_high(CSN);
delay_us(20);

output_low(CSN);
cmd = 0x25; // write register, rf channel
data = 0x02;	// channel 2
	spi_write1(cmd);
	spi_write1(data);
output_high(CSN);
delay_us(20);

output_low(CSN);
cmd = 0x30; // write register, RX address
data = 0xE7;	// set address E7E7E7E7E7
	spi_write1(cmd);
	for(j=0;j<5;j++){
		spi_write1(data);
	}
output_high(CSN);
delay_us(20);

output_low(CSN);
cmd = 0x20; // write register, config
data = 0x3B;	// power up = 1
	spi_write1(cmd);
	spi_write1(data);
output_high(CSN);
output_high(CE);
delay_us(20);
}

// reset all ints
void reset_RX(void){
int data, cmd;

output_low(CSN);
cmd = 0x61; // read rx payload
	//spi_write1(cmd);
	spi_read1(cmd);
output_high(CSN);
delay_us(20);

output_low(CSN);
cmd = 0xE2; // flush rx
data = 0x3A;	// power up = 1
	spi_write1(cmd);
output_high(CSN);
delay_us(20);

output_low(CSN);
cmd = 0x27; // write register STATUS
data = 0x40;	// 
	spi_write1(cmd);
	spi_write1(data);
output_high(CSN);

}


/********************************TX/RX IRQ Interrupt Acknowledgement********************************/

//Main
void main(){
setup_oscillator(OSC_4MHZ|OSC_INTRC);
setup_adc_ports(NO_ANALOGS);	// Set PortA Digital IO
setup_adc(ADC_OFF);				// Turn off ADC
setup_ccp1(CCP_OFF);			// Turn off CCP - will disrupt output writes on PIN_B3 if on
setup_spi(SPI_MASTER|SPI_XMIT_L_TO_H|SPI_CLK_DIV_64);

// set up IRQ (PIN_B0) interrupt for TX/RX notification
//enable_interrupts(INT_EXT);
//ext_int_edge(H_TO_L);
//enable_interrupts(GLOBAL);
//output_low(CE);		// set CE low to disable transmission
output_b(0b00001000);
output_low(LED0 | LED1 | LED2);		// set LEDs Low

delay_ms(2);

output_high(LED0);
RX_mode();
output_low(LED0);

while(1){
int x;
		if(IRQ == 0){
			for(x=0;x<5;x++){
				output_high(LED2);
				delay_ms(100);
				output_low(LED2);
				delay_ms(100);
			}
			delay_ms(200);
			reset_RX();
		}
}

}

Hey rschoele,

I have successfully used the built-in SPI interface. Here’s some of the code I wrote that pertains to accessing the nrf24l01 chip. Unfortunately for you I program in assembly rather than C. Just to be sure are you sure you’ve correctly configured the PIC’s IO port direction so that the SPI interface is working correctly? Can you read data you’ve written to the chip?

;                                       
; SPI Interface variables               
SpiRegOffset    equ     0x30    ; Register offset to write
SpiRegData      equ     0x31    ; Register data to write
SpiStatus       equ     0x32    ; Status value returned when instruction set
SpiData         equ     0x33    ; low level data to be sent and the return data

;
; nRF24L01 constants                    
NRF_R_REG_MASK  equ     0x00            ; Read Register Instruction Mask
NRF_W_REG_MASK  equ     0x20            ; Write Register Instruction Mask
NRF_R_PAYLOAD   equ     0x61            ; Read RX Payload Instruction
NRF_W_PAYLOAD   equ     0xA0            ; Write TX Payload Instruction
NRF_FLUSH_TX    equ     0xE1            ; Flush TX FIFO Instruction
NRF_FLUSH_RX    equ     0xE2            ; Flush RX FIFO Instruction
NRF_REUSE_TX    equ     0xE3            ; Re-use Last TX Payload Instruction
NRF_NOP_INST    equ     0xFF            ; No-Operation Instruction
                                        
; nRF24L01 Memory Mapped Registers      
NRF_CONFIG      equ     0x00            ; Configuration
NRF_EN_AA       equ     0x01            ; Enable Auto Ack
NRF_EN_RXADDR   equ     0x02            ; Enable RX Address
NRF_SETUP_AW    equ     0x03            ; Setup of Address Width
NRF_SETUP_RETR  equ     0x04            ; Setup of Automatic Retransmission
NRF_RF_CH       equ     0x05            ; RF Channel
NRF_RF_SETUP    equ     0x06            ; RF Setup 
NRF_STATUS      equ     0x07            ; Status 
NRF_OBSERVE_TX  equ     0x08            ; Transmit Observe register
NRF_CD          equ     0x09            ; Carrier Detect
NRF_RX_ADDR_P0  equ     0x0A            ; Receive address data pipe 0
NRF_RX_ADDR_P1  equ     0x0B            ; Receive address data pipe 1
NRF_RX_ADDR_P2  equ     0x0C            ; Receive address data pipe 2
NRF_RX_ADDR_P3  equ     0x0D            ; Receive address data pipe 3
NRF_RX_ADDR_P4  equ     0x0E            ; Receive address data pipe 4
NRF_RX_ADDR_P5  equ     0x0F            ; Receive address data pipe 5
NRF_TX_ADDR     equ     0x10            ; Transmit Address
NRF_RX_PW_P0    equ     0x11            ; RX Payload size for data pipe 0
NRF_RX_PW_P1    equ     0x12            ; RX Payload size for data pipe 1
NRF_RX_PW_P2    equ     0x13            ; RX Payload size for data pipe 2
NRF_RX_PW_P3    equ     0x14            ; RX Payload size for data pipe 3
NRF_RX_PW_P4    equ     0x15            ; RX Payload size for data pipe 4
NRF_RX_PW_P5    equ     0x16            ; RX Payload size for data pipe 5
NRF_FIFO_STATUS equ     0x17            ; Fifo Status




; ------------------------------------------------------------------------
; Macro Definitions
;

; Requires approximately 64 cycles
WRITE_REG macro addr, data
        movlw   addr
        movwf   SpiRegOffset
        movlw   data    
        movwf   SpiRegData
        call    WriteDataReg    
        endm

; Requires approximately 62 cycles
READ_REG macro addr     
        movlw   addr    
        movwf   SpiRegOffset    
        call    ReadDataReg     
        endm

; Requires approximately 28 cycles
SET_REUSE_TX macro
        movlw   NRF_REUSE_TX
        movwf   SpiData                 ; W = NRF_REUSE_TX
        bcf     PORT_C,CSN              ; Assert chip select
        call    DoSpiWrite              ; Write the flush instruction
        bsf     PORT_C,CSN              ; Deassert chip select
        endm
        
FLUSH_TX macro
        movlw   NRF_FLUSH_TX
        movwf   SpiData                 ; W = NRF_FLUSH_TX
        bcf     PORT_C,CSN              ; Assert chip select
        call    DoSpiWrite              ; Write the flush instruction
        bsf     PORT_C,CSN              ; Deassert chip select
        endm            
        
FLUSH_RX macro          
        movlw   NRF_FLUSH_RX
        movwf   SpiData                 ; W = NRF_FLUSH_RX
        bcf     PORT_C,CSN              ; Assert chip select
        call    DoSpiWrite              ; Write the flush instruction
        bsf     PORT_C,CSN              ; Deassert chip select
        endm



; ------------------------------------------------------------------------
; Main Code Block
;

; ... PIC init stuff

INIT_RF_CHIP
        ; Initialize nRF24L01
        btfss           PORT_C,MODE
        goto            RF_RX_INIT
        WRITE_REG       NRF_CONFIG, NRF_CONFIG_TX_INIT
        WRITE_REG       NRF_EN_RXADDR, 0x00
        call            SetXmitAddr
        goto            RF_COMMON_INIT

RF_RX_INIT
        WRITE_REG       NRF_CONFIG, NRF_CONFIG_RX_INIT
        WRITE_REG       NRF_EN_RXADDR, NRF_EN_RXADDR_INIT
        WRITE_REG       NRF_RX_PW_P0, NRF_RX_PAYLOAD_INIT
        call            SetRcvAddr

RF_COMMON_INIT
        WRITE_REG       NRF_EN_AA, NRF_EN_AA_INIT
        WRITE_REG       NRF_SETUP_AW, NRF_SETUP_AW_INIT
        WRITE_REG       NRF_SETUP_RETR, NRF_SETUP_RETR_INIT
        
        ; Setup RF Channel (frequency)
        call            SelectFreq
        movwf           SpiRegData
        movlw           NRF_RF_CH
        movwf           SpiRegOffset
        call            WriteDataReg
        
        ; Setup transmission rate
        call            SelectSpeed
        movwf           SpiRegData
        movlw           NRF_RF_SETUP
        movwf           SpiRegOffset
        call            WriteDataReg

; ...main code



; ------------------------------------------------------------------------
; Main Code Subroutines 
;       

; WriteDataReg: Write to a control register through the SPI interface
;       
; On Entry: SpiRegOffset - Set to the register offset value
;           SpiRegData   - Data to load
;       
; On Exit: none         
;       
; calling limit: callable by any routine
;       
; Requires approximately 58 cycles
;       
WriteDataReg
        movlw   NRF_W_REG_MASK
        movwf   SpiData                 ; W = NRF_W_REG_MASK
        movf    SpiRegOffset,W
        iorwf   SpiData,F               ; SpiData = NRF_W_REG_MASK | regOffset
        bcf     PORT_C,CSN              ; Assert chip select
        call    DoSpiWrite              ; Write the address instruction
        movf    SpiRegData,W
        movwf   SpiData 
        call    DoSpiWrite              ; Write the actual data
        bsf     PORT_C,CSN              ; Deassert chip select
        return

       
; ReadDataReg: Read from a control register through the SPI interface
;       
; On Entry: SpiRegOffset - Set to the register offset value
;       
; On Exit: SpiRegData contains data from read
;       
; calling limit: callable by any routine
;       
; Requires approximately 58 cycles
;       
ReadDataReg
        movlw   NRF_R_REG_MASK
        movwf   SpiData                 ; W = NRF_R_REG_MASK
        movf    SpiRegOffset,W
        iorwf   SpiData,F               ; SpiData = NRF_R_REG_MASK | regOffset
        bcf     PORT_C,CSN              ; Assert chip select
        call    DoSpiWrite              ; Write the address instruction
        call    DoSpiWrite              ; Get the actual data
        bsf     PORT_C,CSN              ; Deassert chip select
        movf    SpiData,W
        movwf   SpiRegData              ; Return read data return
        return


; DoSpiWrite: Cause the PIC to execute one SPI byte operation
;
; On Entry: SpiData contains value to send
;
; On Exit: SpiData contains data read back in
;
; calling limit: callable by the SPI Interface routines
;
; Requires approximately 22 cycles
;
DoSpiWrite
        movf    SpiData,W
        movwf   SSPBUF                  ; Triggers write
DoSpiWrite1
        btfss   PIR1,SSPIF              ; Spin until SSPIF is set
        goto    DoSpiWrite1
        bcf     PIR1,SSPIF              ; Make sure status is clear
        movf    SSPBUF,W
        movwf   SpiData                 ; return incoming data
        return

And here’s the code that actually performs the transmission and reception of data. This code has a two-byte payload. Byte 0 is the control byte which contains a sequence number (because this code sent the same packet multiple times). Byte 1 is the actual data. In order to minimize overhead I only used the ISR to set a flag indicating I’d seen an interrupt from the nrf chip. For timing (I believe in the tx loop I didn’t want the overhead of saving/restoring PIC state).

; ------------------------------------------------------------------------
; Main Code Block
;
; The Main Code Block performs the initialization and main tx/rx loops.
;

        ; ----------------------------------------------------------------
        ; Reset Vector
        org             0x0
        goto            MAIN_VECTOR

        ; ----------------------------------------------------------------
        ; Interrupt Vector
        org             0x4
        bsf             Flags,SawInterrupt
        bcf             INTCON,INTF_INT         ; Clear the interrupting condition
        retfie

        ; ----------------------------------------------------------------
        ; Start of main initialization code
        ;
        org             MAIN_VECTOR
MAIN_VECTOR

        ; Initialize common PIC control registers in page 0...

INIT_VARS
        ; Initialize common variables
        clrf            Flags
        btfss           PORT_C,MODE
        goto            RX_VAR_INIT
        ; TX-mode specific variables
        movlw           STATUS_TIMER_TX_INIT
        movwf           CurStatusTimer
        clrf            CurSeqNum
        goto            INIT_RF_CHIP

RX_VAR_INIT
        ; RX-mode specific variables
        movlw           STATUS_TIMER_RX_INIT
        movwf           CurStatusTimer
        movlw           0xFF
        movwf           CurSeqNum

; nRF init as shown in the previous post...

        ; ----------------------------------------------------------------
        ; Start of main TX-mode loop
        ;   - Check for any incoming serial data
        ;     - Send the character
        ;     - Clear any set status LEDs periodically
        ;
MAIN_TX_LOOP
        clrwdt                          ; Clear the watchdog timer

        ; Delay ~ 12.5 msec, checking for a new character every 50 uSec
        movlw           .250
        movwf           Temp
MAIN_TX_DLY
        MAIN_DELAY      .5              ; 50 uSec
        ; Check for an incoming character from the serial interface
        btfsc           PIR1,RCIF
        call            HandleSIFCharacter
        
        decfsz          Temp,F
        goto            MAIN_TX_DLY
        
        ; Check if it is time to clear any set status LEDs
        decfsz          CurStatusTimer,F
        goto            MAIN_TX_LOOP
        ; Reset timer and clear status LEDs
        movlw           STATUS_TIMER_TX_INIT
        movwf           CurStatusTimer
        bsf             PORT_A,BUFF_OVRFL
        goto            MAIN_TX_LOOP


        ; Start of main RX-mode loop
        ;   - Spin (will be interrupted when a packet is received)
        ;     Transmit any received characters through the serial interface
        ;     and check the carrier detect register and clear any set status
        ;     LEDs periodically.
        ;
MAIN_RX_LOOP
        ; Set CE to enable the receiver
        bsf             PORT_C,CE
        
        ; Initialize TIMER1
        movlw           RX_TIMER1L_INIT
        movwf           TMR1L
        movlw           RX_TIMER1H_INIT
        movwf           TMR1H
        movlw           T1CON_SETUP
        movwf           T1CON

MAIN_RX_LOOP_1
        clrwdt                          ; Clear the watchdog timer

        btfsc           Flags,SawInterrupt
        call            HandleRFCharacter

        ; Check for timer overflow every 100 mSec
        btfss           PIR1,TMR1IF
        goto            MAIN_RX_LOOP_1

        ; Reset TIMER1
        bcf             PIR1,TMR1IF
        movlw           RX_TIMER1L_INIT
        movwf           TMR1L
        movlw           RX_TIMER1H_INIT
        movwf           TMR1H

        ; read carrier detect
;       bcf             INTCON,GIE              ; Disable interrupts
;       READ_REG        NRF_CD
;       bsf             PORT_A,CARRIER_DET      ; Update CD status
;       btfsc           SpiRegData,.0
;       bcf             PORT_A,CARRIER_DET
;       bsf             INTCON,GIE              ; Re-enable interrupts

        ; Check if it is time to clear any set status LEDs
        decfsz          CurStatusTimer,F
        goto            MAIN_RX_LOOP_1 
        ; Reset timer and clear status LEDs
        movlw           STATUS_TIMER_RX_INIT
        movwf           CurStatusTimer
        bsf             PORT_A,SEQ_MISMATCH
        bsf             PORT_A,BUFF_OVRFL
        goto            MAIN_RX_LOOP_1



; ------------------------------------------------------------------------
; Main Code Subroutines
;


; WriteTxPayload: Write the payload through the SPI interface
;
; On Entry: SpiBufX loaded to send
;
; On Exit: none
; 
; Requires approximately 82 cycles
;
WriteTxPayload  
        movlw   NRF_W_PAYLOAD
        movwf   SpiData
        bcf     PORT_C,CSN              ; Assert chip select
        call    DoSpiWrite              ; Write the address instruction
        movf    SpiBuf0,W
        movwf   SpiData
        call    DoSpiWrite              ; load buf 0
        movf    SpiBuf1,W
        movwf   SpiData
        call    DoSpiWrite              ; load buf 1
        bsf     PORT_C,CSN              ; Deassert chip select
        return


; ReadRxPayload: Read the payload through the SPI interface
; 
; On Entry:
; 
; On Exit: SpiBufX loaded with RX data
; 
; Requires approximately 82 cycles
;
ReadRxPayload   
        movlw   NRF_R_PAYLOAD
        movwf   SpiData
        bcf     PORT_C,CSN              ; Assert chip select
        call    DoSpiWrite              ; Write the address instruction
        call    DoSpiWrite              ; get buf 0
        movf    SpiData,W
        movwf   SpiBuf0
        call    DoSpiWrite              ; get buf 1
        bsf     PORT_C,CSN              ; Deassert chip select
        movf    SpiData,W
        movwf   SpiBuf1
        return

; HandleSIFCharacter: Handler routine for incoming serial communication.
; This routine is called whenever a character is received from the USART.
;
; on entry:  At least one character in the RCREG
;
; on exit: Character sent through RF interface
;
; calling limit: callable by any routine
;
; Notes:
;   1. Code overhead (main loop delay to SEND_RF_CHAR 1) is around 106 uSec
;   2. Initial packet transmission is around 128 (chip processing) +
;    + [37 uSec (payload overhead) + 8 uSec (2-byte payload)] (@ 2 Mpbs)
;    + [74 uSec (payload overhead) + 16 uSec (2-byte payload)] (@ 1 Mpbs)
;    = 173 uSec @ 2 Mbps, 218 uSec @ 1Mbps
;   3. Each repeated packet requires around 40 uSec (2 Mbps) / 80 uSec (1 Mpbs)
;
HandleSIFCharacter
        ; Check the RX status
        btfsc           RCSTA,FERR      ; Check for framing error
        goto            BAD_RX_STATUS   ;   Framing error
        btfss           RCSTA,OERR      ; Check for overrun
        goto            GET_RX_CHAR     ;   no overrun
                                        ;   overrun
        movf            RCREG,W         ; Drain entry 1 of the RX FIFO
        bcf             PORT_A,BUFF_OVRFL       ; Set indication of overflow (LED)
        bsf             PORT_A,BUFF_OVRFL_P     ; Set indication of overflow (pulse)
        nop
        bcf             PORT_A,BUFF_OVRFL_P     ; Set indication of overflow (pulse)
BAD_RX_STATUS
        movf            RCREG,W         ; Drain entry 2 of the RX FIFO or clear
                                        ;   badly framed character
        bcf             RCSTA,CREN      ; Reset the RX port and clear errors
        bsf             RCSTA,CREN
        return

GET_RX_CHAR
        movf            RCREG,W
        movwf           SerialChar

SEND_RF_CHAR
        ; Setup to send a packet repeatedly
        movf            TxRepeatCount,W 
        movwf           CurRepeatCount  ; CurRepeatCount = TxRepeatCount
        
        movf            CurSeqNum,W     ; Load the transmit buffer
        movwf           SpiBuf0
        movf            SerialChar,W
        movwf           SpiBuf1
        call            WriteTxPayload
        
        bcf             PORT_A,PKT_ACTIVITY     ; Set the packet activity status
        
        SET_REUSE_TX                    ; Configure automatic packet resend
        
        bsf             PORT_C,CE       ; Trigger the transmission
        bcf             Flags,SawInterrupt

SEND_RF_CHAR_1 
        ; Spin waiting for the ISR to indicate packet transmitted
        btfss           Flags,SawInterrupt
        goto            SEND_RF_CHAR_1
        bcf             Flags,SawInterrupt
        
        WRITE_REG       NRF_STATUS, 0x70        ; Clear pending interrupts
        
        ; Check if we've sent the specified number (minus 1) of repeated packets
        decfsz          CurRepeatCount,F
        goto            SEND_RF_CHAR_1
        
        bcf             PORT_C,CE       ; De-assert CE (min time met by WRITE_REG above)

SEND_RF_CHAR_2 
        ; Spin waiting for the ISR to indicate final packet transmitted
        btfss           Flags,SawInterrupt
        goto            SEND_RF_CHAR_2
        bcf             Flags,SawInterrupt
        
        WRITE_REG       NRF_STATUS, 0x70        ; Clear pending interrupts
        
        ; Setup for next character
        incf            CurSeqNum,F
        bsf             PORT_A,PKT_ACTIVITY     ; Clear the packet activity status
        return


; SendSIFCharacter: Routine to send a character through the serial interface.
; This routine is called whenever a character needs to be sent to the USART.
;
; on entry: SerialChar contains the character to send
;
; on exit: Character sent through USART interface
;          RcvCharValid cleared
;
; calling limit: callable by any routine
;
; Notes:
; This can be made more reliable by taking interrupts on TXIF so we can
; manage a flag indicating when TXREG is empty/full and can detect overflow here...
; Or not call this routine if TXREG is not available
;
SendSIFCharacter
        ; Spin until the TXREG is available
        btfss           PIR1,TXIF
        goto            SendSIFCharacter
        movf            SerialChar,W
        movwf           TXREG
        bcf             Flags,RcvCharValid
        return



; HandleRFCharacter : Handle any and all data from the RX FIFO
;        Checks Sequence Number
;             if = Current Sequence Number => already received this packet
;             if = Current Sequence Number + 1 => New data
;                 Note Buffer overflow if RcvCharValid set
;                 Load SerialChar and set RcvCharValid
;                 Increment Sequence Number
;             else
;                 Note sequence error
;                 Note Buffer overflow if RcvCharValid set
;                 Load SerialChar and set RcvCharValid
;                 Reset Sequence Number
;        Resets nRF24L01 Status register
;
; on entry: Data available in the RX FIFO
;
; on exit: FIFO should be clear
;
; calling limit: callable by any routine
;
; Notes:
;   RX Mode timing:
;     1. Delay from start-of-interrupt to HANDLE_RF_CHAR_1 is around 4-5 uSec
;     2. Processing delay for each 2-byte payload is around :
;        154 cycles for repeated data (61.6 uSec)
;        173 cycles for initial data (69.2 uSec)
;
;   Data drain rate from FIFO is 74 + (N-1)*61.6 where N is the number of incoming packets
;
HandleRFCharacter
        bcf             PORT_A,PKT_ACTIVITY     ; Set the packet activity status
HANDLE_RF_CHAR_1
        call            ReadRxPayload

        ; check Sequence Number in SpiBuf0
        movf            SpiBuf0,W               ; W = received Sequence Number
        subwf           CurSeqNum,W             ; W = CurSeqNum - received Sequence Num
        btfsc           STATUS,Z                ; Equal?
        goto            HANDLE_RF_CHAR_3        ;   Y: Already got this data
                                                ;   N: New data
        incf            CurSeqNum,F             ; CurSeqNum++
        movf            SpiBuf0,W               ; W = received Sequence Number
        subwf           CurSeqNum,W             ; W = next CurSeqNum - received Sequence Num
        btfsc           STATUS,Z                ; Equal?
        goto            HANDLE_RF_CHAR_2        ;   Y: Next data in sequence
                                                ;   N: Missed sequence number
        movf            SpiBuf0,W
        movwf           CurSeqNum               ; Reset CurSeqNum to this new sequence num
        bcf             PORT_A,SEQ_MISMATCH     ; Set sequence number mismatch status LED
        bsf             PORT_A,SEQ_MISMATCH_P   ; Sequence number mismatch status (pulse)
        nop
        bcf             PORT_A,SEQ_MISMATCH_P

HANDLE_RF_CHAR_2
        ; Get data and load it into the serial port
        movf            SpiBuf1,W
        movwf           SerialChar
        btfsc           Flags,RcvCharValid      ; Check if RcvCharValid already set
        goto            HANDLE_RF_CHAR_OVRFL    ;   Y : overflow
        bsf             Flags,RcvCharValid      ;   N : set RcvCharValid
        call            SendSIFCharacter
        goto            HANDLE_RF_CHAR_3

HANDLE_RF_CHAR_OVRFL
        bcf             PORT_A,BUFF_OVRFL       ; Set buffer overflow (LED)
        bsf             PORT_A,BUFF_OVRFL_P     ; Set indication of overflow (pulse)
        nop
        bcf             PORT_A,BUFF_OVRFL_P     ; Set indication of overflow (pulse)

HANDLE_RF_CHAR_3
        ; Check if there is any additional data in the RX FIFO
        READ_REG        NRF_FIFO_STATUS
        btfss           SpiRegData,.0           ; RX_EMPTY?
        goto            HANDLE_RF_CHAR_1        ;   N: Get more data
                                                ;   Y: Prepare for the next data packet
        bcf             Flags,SawInterrupt
        WRITE_REG       NRF_STATUS, 0x70        ; Clear pending interrupts
        bsf             PORT_A,PKT_ACTIVITY     ; Clear the packet activity status
        return

mmm…and for completeness, here are the actual values I program into the nRF24L01:

; nRF24L01 Initialization constants
NRF_CONFIG_TX_INIT      equ     B'01011110' ; 7: Reserved = 0
                                        ; 6: MASK_RX_DR = 1 (Mask RX_DR int)
                                        ; 5: MASK_TX_DR = 0 (Allow TX_DS int)
                                        ; 4: MASK_MAX_RT = 1 (Mask MAX_RT int)
                                        ; 3: EN_CRC = 1 (enable CRC)
                                        ; 2: CRC0 = 1 (2 byte CRC)
                                        ; 1: PWR_UP = 1
                                        ; 0: PRIM_RX = 0 (PTX mode)

NRF_CONFIG_RX_INIT      equ     B'00111111' ; 7: Reserved = 0
                                        ; 6: MASK_RX_DR = 0 (Allow RX_DR int)
                                        ; 5: MASK_TX_DR = 1 (Mask TX_DS int)
                                        ; 4: MASK_MAX_RT = 1 (Mask MAX_RT int)
                                        ; 3: EN_CRC = 1 (enable CRC)
                                        ; 2: CRC0 = 1 (2 byte CRC)
                                        ; 1: PWR_UP = 1
                                        ; 0: PRIM_RX = 1 (PRX mode)
;
NRF_EN_AA_INIT  equ     B'00000000'
;
NRF_EN_RXADDR_INIT      equ     B'00000001'     ; 7:6: Reserved = 0
                                        ; 5: Enable data pipe 5 = 0
                                        ; 4: Enable data pipe 4 = 0
                                        ; 3: Enable data pipe 3 = 0
                                        ; 2: Enable data pipe 2 = 0
                                        ; 1: Enable data pipe 1 = 0
                                        ; 0: Enable data pipe 0 = 1

NRF_SETUP_AW_INIT       equ     B'00000011'     ; 7:2: Reserved = 0
                                        ; 1:0: RX/TX Addr width = 11 (5 bytes)

NRF_SETUP_RETR_INIT     equ     B'00000000'

NRF_FREQ_0_INIT         equ     B'00000010'
NRF_FREQ_1_INIT         equ     B'00000100'
NRF_FREQ_2_INIT         equ     B'00001000'
NRF_FREQ_3_INIT         equ     B'00010000'

NRF_RF_SETUP_1_INIT     equ     B'00000111'     ; 1 MBit/sec
NRF_RF_SETUP_2_INIT     equ     B'00001111'     ; 2 MBit/sec

NRF_ADDR0_0_INIT        equ     0xE7            ; LSbyte ADDRESS_0
NRF_ADDR0_1_INIT        equ     0xE7
NRF_ADDR0_2_INIT        equ     0xE7
NRF_ADDR0_3_INIT        equ     0xE7
NRF_ADDR0_4_INIT        equ     0xE7            ; MSbyte ADDRESS_0
NRF_ADDR0_3_INIT        equ     0xE7
NRF_ADDR0_4_INIT        equ     0xE7            ; MSbyte ADDRESS_0

NRF_ADDR1_0_INIT        equ     0xC2            ; LSbyte ADDRESS_1
NRF_ADDR1_1_INIT        equ     0xC2
NRF_ADDR1_2_INIT        equ     0xC2
NRF_ADDR1_3_INIT        equ     0xC2
NRF_ADDR1_4_INIT        equ     0xC2            ; MSbyte ADDRESS_1

NRF_ADDR2_0_INIT        equ     0xC3            ; LSbyte ADDRESS_2
NRF_ADDR2_1_INIT        equ     0xC3
NRF_ADDR2_2_INIT        equ     0xC3
NRF_ADDR2_3_INIT        equ     0xC3
NRF_ADDR2_4_INIT        equ     0xC3            ; MSbyte ADDRESS_2

NRF_ADDR3_0_INIT        equ     0xC4            ; LSbyte ADDRESS_3
NRF_ADDR3_1_INIT        equ     0xC4
NRF_ADDR3_2_INIT        equ     0xC4
NRF_ADDR3_3_INIT        equ     0xC4
NRF_ADDR3_4_INIT        equ     0xC4            ; MSbyte ADDRESS_3

NRF_RX_PAYLOAD_INIT     equ     .2              ; Sequence + Data

TX_REPEAT_CNT_1M_2400   equ     .43
TX_REPEAT_CNT_1M_4800   equ     .20
TX_REPEAT_CNT_1M_9600   equ     .7
TX_REPEAT_CNT_1M_19200  equ     .1

TX_REPEAT_CNT_2M_2400   equ     .43
TX_REPEAT_CNT_2M_4800   equ     .43
TX_REPEAT_CNT_2M_9600   equ     .17
TX_REPEAT_CNT_2M_19200  equ     .4

; Global Constants
STATUS_TIMER_TX_INIT    equ     .80             ; 1 second @ 12.5 msec intervals
STATUS_TIMER_RX_INIT    equ     .10             ; 1 second @ 100 msec intervals
RX_TIMER1L_INIT         equ     0xEE            ; TIMER1 initialization values
RX_TIMER1H_INIT         equ     0x85            ;  to cause rollover ever 100 msec

and the routines to set the address:

; SelectFreq: Return the correct nRF24L01 RF Channel register initialization
; value based on the input pin strapping.
;
; on entry: Channel input pins strapped to desired value
;       
; on exit: W contains the initialization value
;       
; calling limit: callable by any routine
;       
SelectFreq
        clrw
        btfsc           PORT_B,CHANNEL_0
        iorlw           0x01            ; W[0] set if CHANNEL_0 set
        btfsc           PORT_B,CHANNEL_1
        iorlw           0x02            ; W[1] set if CHANNEL_1 set
        addwf           PCL,F           ; Jump into table below
        retlw           NRF_FREQ_0_INIT ; 00
        retlw           NRF_FREQ_1_INIT ; 01
        retlw           NRF_FREQ_2_INIT ; 10
        retlw           NRF_FREQ_3_INIT ; 11


; SelectSpeed: Return the correct nRF24L01 RF Setup register initialization
;
; on entry: Speed input pin strapped to desired value
;       
; on exit: W contains the initialization value 
;       
; calling limit: callable by any routine
;       
SelectSpeed
        clrw
        btfsc           PORT_B,SPEED
        iorlw           0x01                    ; W[0] set if SPEED set
        addwf           PCL,F                   ; Jump into table below
        retlw           NRF_RF_SETUP_1_INIT     ; 0
        retlw           NRF_RF_SETUP_2_INIT     ; 1

; SetXmitAddr: Configure the nRF24L01 transmit address based on the input
; pin strapping.
;
; on entry: Address pins strapped to desired value
;
; on exit: nRF24L01 transmit address registers updated
;
SetXmitAddr
        movlw           NRF_TX_ADDR
        movwf           SpiRegOffset
        call            SetAddr
        return


; SetRcvAddr: Configure the nRF24L01 Pipe 0 receive address based on the
; input pin strapping.
; 
; on entry: Address pins strapped to desired value
; 
; on exit: nRF24L01 pipe 0 receive address registers updated
;
SetRcvAddr
        movlw           NRF_RX_ADDR_P0
        movwf           SpiRegOffset
        call            SetAddr
        return


; SetAddr: Configure the specified 40-bit nRF24L01 address register
; 
; on entry: Address pins strapped to desired value (0 - 3)
;           SpiRegOffset contains the register to update
; 
; on exit: specified register written with selected 40-bit address
;
SetAddr 
        ; Setup to write the 5 byte address
        movlw           NRF_W_REG_MASK
        movwf           SpiData
        movf            SpiRegOffset,W  
        iorwf           SpiData,F       ; SpiData = NRF_W_REG_MASK | <register offset>
        bcf             PORT_C,CSN
        
        ; Select the address
        btfsc           PORT_B,ADDRESS_SEL_1
        goto            SET_ADDR_CHECK_1
        btfsc           PORT_B,ADDRESS_SEL_0
        goto            SET_ADDR_1

        ; Address 0
        call            DoSpiWrite              ; Write the address instruction
        movlw           NRF_ADDR0_0_INIT
        movwf           SpiData
        call            DoSpiWrite
        movlw           NRF_ADDR0_1_INIT
        movwf           SpiData
        call            DoSpiWrite
        movlw           NRF_ADDR0_2_INIT
        movwf           SpiData
        call            DoSpiWrite
        movlw           NRF_ADDR0_3_INIT
        movwf           SpiData
        call            DoSpiWrite
        movlw           NRF_ADDR0_4_INIT
        movwf           SpiData
        call            DoSpiWrite
        bsf             PORT_C,CSN
        return

SET_ADDR_1
        ; Address 1
        call            DoSpiWrite              ; Write the address instruction
        movlw           NRF_ADDR1_0_INIT
        movwf           SpiData
        call            DoSpiWrite
        movlw           NRF_ADDR1_1_INIT
        movwf           SpiData
        call            DoSpiWrite
        movlw           NRF_ADDR1_2_INIT
        movwf           SpiData
        call            DoSpiWrite
        movlw           NRF_ADDR1_3_INIT
        movwf           SpiData
        call            DoSpiWrite
        movlw           NRF_ADDR1_4_INIT
        movwf           SpiData
        call            DoSpiWrite
        bsf             PORT_C,CSN
        return

SET_ADDR_CHECK_1
        btfsc           PORT_B,ADDRESS_SEL_0
        goto            SET_ADDR_3

        ; Address 2
        call            DoSpiWrite              ; Write the address instruction
        movlw           NRF_ADDR2_0_INIT
        movwf           SpiData
        call            DoSpiWrite
        movlw           NRF_ADDR2_1_INIT
        movwf           SpiData
        call            DoSpiWrite
        movlw           NRF_ADDR2_2_INIT
        movwf           SpiData
        call            DoSpiWrite
        movlw           NRF_ADDR2_3_INIT
        movwf           SpiData
        call            DoSpiWrite
        movlw           NRF_ADDR2_4_INIT
        movwf           SpiData
        call            DoSpiWrite
        bsf             PORT_C,CSN
        return

SET_ADDR_3
        ; Address 3
        call            DoSpiWrite              ; Write the address instruction
        movlw           NRF_ADDR3_0_INIT
        movwf           SpiData
        call            DoSpiWrite
        movlw           NRF_ADDR3_1_INIT
        movwf           SpiData
        call            DoSpiWrite
        movlw           NRF_ADDR3_2_INIT
        movwf           SpiData
        call            DoSpiWrite
        movlw           NRF_ADDR3_3_INIT
        movwf           SpiData
        call            DoSpiWrite
        movlw           NRF_ADDR3_4_INIT
        movwf           SpiData
        call            DoSpiWrite
        bsf             PORT_C,CSN
        return

Just to be sure are you sure you’ve correctly configured the PIC’s IO port direction so that the SPI interface is working correctly? Can you read data you’ve written to the chip?

I’m not sure - as far as i understand when using the ‘setup_spi()’ call in the 16f88 device header file the IO ports should configure automatically - I use #use standard_io, which means the compiler configures the IO based on the code. When using SPI the specific pins I define are the ones that according to the PIC data sheet are the TX,RX and SCK pins.

But I was waiting for a reply to ask a question pertaining to this. I have logic analyzer and I see the data go out the MOSI pin I set, I see the CLK as well. I’m not sure, according to the nRF24L01 data sheet how MISO works exactly - am I supposed to see a byte clocked back to the PIC simultaneously as I clock out data? or is it a separate command I have to send?

thanks

rschoele

I’m not sure, according to the nRF24L01 data sheet how MISO works exactly - am I supposed to see a byte clocked back to the PIC simultaneously as I clock out data? or is it a separate command I have to send?

Yup, SPI interfaces clock a bit out for every bit you clock in. The nRF24L01 clocks out its STATUS register when you load the instruction byte (i.e. read/write command and register address).

I’m not sure what it clocks out for write ‘data’ bytes, my code just ignores this information.

When reading data from the chip, I just clock in garbage (whatever is in one of my PIC registers - the SpiData register). Since the chip has been configured for reading it must just ignore this data.

So you should have a total of 4 wires connected to the chip for the SPI interface. SCLK, MOSI (PIC SDO), MISO (PIC SDI) and an active low CSN signal.

Then you also need to drive the active high CE signal and receive the active low IRQ for RF operation.

It seems writing C for the PIC is quick and easy. How about creating a simple test program that writes one or more registers and then tries to read them back? Using the logic analyzer (lucky guy…) you should be able to track down any problems. I understand your frustration, getting the nRF24L01 to work for my application was a lot of little steps. But it does seem to work exactly like Nordic claims in the spec. I’ve now moved many many megabytes of data through it successfully.

my wiring is like you state (I’ve looked at it a million times :roll: hoping that would be the problem). So say when I write to the CONFIG register (address 0x00) I should see the 8bit value I write to that register on the MISO pin? Or will I see the STATUS (address 0x07)?

I’ll go back to some basics like you suggest, cause right now I don’t see anything clocked back.

It seems writing C for the PIC is quick and easy. How about creating a simple test program that writes one or more registers and then tries to read them back?

So I guess this is some of my confusion and I’m reading that quote literally so I’ll need you to clarify – C is quick and easy and I can call the SPI like so

data = spi_read(data1);

This should simultaneoulsy pass ‘data1’ out the MISO and clock in the MOSI to ‘data’ - but is what you’re saying that there won’t be anything to clock in until AFTER I’ve written something out? In other words, should

I call an ‘spi_write(data1)’ then ‘spi_read(data)’

Of course I’ll be trying these methods in the meantime - thanks much and thanks for the code - the assembler is one of those things I tell myself I’ll learn, but like you said ‘C is easy’ :smiley: unless it doesn’t work!

:frowning: hmmm - can’t get anything back from MISO using SPI - I’m running relatively slow osc (4MHZ) I’ve tried all the clk/div, tried all output configurations (i.e. H_to_L, L_to_H) - I’m missing something here.

gonna try bit banging

Turns out my use of the built-in SPI doesnt’ work.

Bit-banging did work and I have basic comm.

thanks for the help

Ryan

Well I’m glad to hear you got it working. Strange that the built-in SPI doesn’t work. I did have one thought about this. Have you looked at the assembly produced by the C compiler? Perhaps there is a bug there. I don’t know how the various functions you are using to initialize the SPI interface are written but perhaps there is a bug in one of them.

anyway, good luck with your project!

yeh I thought about that - when comparing the SPI set up options provided in the device header file to the datasheet. It doesn’t seem like I have all the options available for configuring the SPI, but then again it takes me several reads to understand this stuff.

But for now my bit-banging is working so I’m not going to sweat it.

thanks for your help.

Hi, I always had troubles in “realizing” how the Modes for SPI (CPOL, PHASE ecc.) do work! :evil:

When I use bit-bang, instead, things are easier to realize. Probably you may have that kind of issue too!

I have followed this discussion and used the SparkFun sample code to create my own test communication between a Tx and Rx. instead of the Pic F88, I use the Pic F690 which is very similar. However, when I check the output of the receiver buffer I get nothing but four bytes of zero data. I do get interrupts at the Rx and I did set up CRC, so is this implying that the CRC did work properly and that the zero data was transmitted Therefore, this seems to indicate that the data that I intended to transmit did not clock into the transmit buffer properly.

Can anyone tell me what is happening here and how to fix it? Did anyone get the nRF24L01 sample code to work as expected (i.e. actual data transmitted between two devices with F88 handling the SPI)?