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