MEL PICBASIC Forum - NRF24L01+ CODE Example for 1 to 1 data communication using same code on 2 PICs.


  • NRF24L01+ CODE Example for 1 to 1 data communication using same code on 2 PICs.

    '************************************************* ***************
    ; This code allows for data communication between 2 NRF24L01+
    ; modules running on a PIC microcontroller using the MSSP module.
    ; In my version of the code, I use DT-18 interrutps to increment a counter once
    ; every 500ms. When the counter reaches 10, the PIC sets the module up in TX mode
    ; and transmits 5 bytes. When it has completed, it will pause for 25us and
    ; wait for the IRQ pin to go low so that it could be reset by the user.
    ;
    ; There are no Automatic Acknowledge Functions enabled and also no Re-Transmit
    ; Functions enabled. The settings are for bare-bones use only.
    ;
    ; No settings for the MSSP module are listed as the register settings vary from
    ; PIC to PIC. Variables and constants are listed.
    ; Data transfer is at 1Mpbs at 0dbm. It allows for up to 32 bytes to be transmitted
    ; and received using the same code on each PIC. You would just need to make the array
    ; to your desired size and adjust the configuration accordingly.
    ; This code was inspired from forum member vancalst, http://sites.google.com/site/avcnetsite/mcu.
    ; His is a very good project I might add!
    '************************************************* ***************


    ;*-*-*-*-*BE SURE TO INCLUDE THE DT_INTS FOR WHATEVER PIC YOU'RE WORKING WITH *-*-*-*-*

    Code:
    ;******************************************************************************
    ;Constants.
    ;******************************************************************************
    ; SPI NRF24L01 commands
        ReadCmd         con    $00          ; Read command to read registers.
        WriteCmd        con    $20          ; Write command to write to registers.
        ReadRxPld       con    $61          ; Read Rx payload register address.
        WriteTxPld      con    $A0          ; Write Tx payload register address.
        FlushTx         con    $E1          ; Flush Tx register command.
        FlushRx         con    $E2          ; Flush Rx register command.
        ReuseTxPld      con    $E3          ; Reuse Tx payload register command.
        NoOperate       con    $FF          ; No operation, for reading STATUS register.
        
    ;******************************************************************************
    ; SPI NRF24L01 registers addresses
        ConfigAddr      con    $00          ; Config register, address $00.                  
        EnAAAddr        con    $01          ; Auto Acknowledgement Function register, address $01.
        EnRxAddr        con    $02          ; Enable the Receiver register, address $02.
        SetupAWAddr     con    $03          ; Setup Address Widths of Data Pipes, register address $03.
        SetupReTxAddr   con    $04          ; Setup Automatic Retransmission register, address $04.     
        SetupRfChAddr   con    $05          ; RF Channel selection regsiter, address, $05. Channels 0 to 127.
        RfSetupAddr     con    $06          ; RF setup register address.
        StatusAddr      con    $07          ; Status register address.
        ObsrvTxAddr     con    $08          ; Observe TX register address.
        CardetectAddr   con    $09          ; NRF_Carrier detect register address.
        RxPipe0Addr     con    $0A          ; NRF_RX Pipe 0 register address.
        RxPipe1Addr     con    $0B          ; NRF_RX pipe 1 register address.
        RxPipe2Addr     con    $0C          ; NRF_RX pipe 2 register address.
        RxPipe3Addr     con    $0D          ; NRF_RX pipe 3 register address.
        RxPipe4Addr     con    $0E          ; NRF_RX pipe 4 register address.
        RxPipe5Addr     con    $0F          ; NRF_RX pipe 5 register address.
        TxADDRAddr      con    $10          ; NRF_TX AdDRESS register address.
        RxPwPipe0Addr   con    $11          ; NRF_RX payload width pipe0 register address.
        RxPwPipe1Addr   con    $12          ; NRF_RX payload width pipe1 register address.
        RxPwPipe2Addr   con    $13          ; NRF_RX payload width pipe2 register address.
        RxPwPipe3Addr   con    $14          ; NRF_RX payload width pipe3 register address.
        RxPwPipe4Addr   con    $15          ; NRF_RX payload width pipe4 register address.
        RxPwPipe5Addr   con    $16          ; NRF_RX payload width pipe5 register address.
        FifoStatAddr    con    $17          ; NRF_FIFO status register register address.
        DynPldAddr      con    $1C          ; NRF_DYNPD Enable dynamic payload register address.
        FeatureAddr     con    $1D          ; NRF_Feature register address.
        
    ;******************************************************************************
    ; Port Pin names.
    ;*******************************************************************************
        HeartBeat   var     PORTX.Y
        NrfChipEn   var     PORTX.Y
        NrfChipSel  var     PORTX.Y
        NrfMosi     var     PORTX.Y
        NrfMiso     var     PORTX.Y
        NrfClock    var     PORTX.Y
        NrfIRQ      var     PORTX.Y
    
    
    ;*******************************************************************************
    ; Variables listing.
    ;*******************************************************************************
        SPICounter          var byte    ; General Puspose Counter.
        RxTxCounter         var byte    ; General Puspose Counter.
    
        NrfRxPckt           var byte[8]     
        NrfTxPckt           var byte[8] 
    
        WriteBytes          var byte
        Readbytes           var byte
        ReadSPIBuffer       var byte
    
    ;*******************************************************************************
    ;ASM INTERRUPTS COURTESY OF DARREL TAYLOR.    
    ASM
    INT_LIST  macro  ;  IntSource,       Label,             Type,   ResetFlag? 
        INT_Handler     TMR1_INT,       _Heart_Beat,        PBP,    YES        
        endm      
        INT_CREATE              ; Creates the interrupt processor    
    ENDASM
    
    
    ;*******************************************************************************
        goto Start
    
    ;*******************************************************************************
    Heart_Beat: 
        toggle HeartBeat 
         RxTxCounter = RxTxCounter + 1
    @ INT_RETURN
    
    
    ;*******************************************************************************
    ;******************************************************************************* 
    ;*******************************************************************************
    Start: 
        clear
        SSPEN = 1                                ; Enable SPI pins
        NrfChipEn = 1                            ; Enable the NRF Module.
        NrfChipSel = 1                           ; Disable the NRF Module.
        pause 500                                ; Wait 500ms for the rest of the system to power up.
    
    
    InitNRF:  ; All Common registers are written to sequentially, $01 - $1D. The WRITE command includes
              ; the regsiter address being written to. A data byte must followed the Write 
              ; command. It will contain the information needing to be changed. 
    
    
        ; Writing to Address $01 
        NrfTxPckt[0] = WriteCmd + EnAAAddr       ; Read/Write to the EN_AA REGISTER Address $01.
        NrfTxPckt[1] = 000000                 ; Data for EnAAAddr REGISTER Address $01. Disable all Auto Acknowledge Functions.
        WriteBytes = 1                           ; Number of byte to write to SPI module. 0 = 1 byte, counts from 0 to ?
        gosub NrfSPIWrite                        ; Send data to the Nrf Module.
        
        ; Writing to Address $02 
        NrfTxPckt[0] = WriteCmd + EnRxAddr       ; Read/Write to the EN_RXADDR REGISTER Address $02.
        NrfTxPckt[1] = 000001                 ; Data for EnAAAddr REGISTER Address $02. Enable Data Pipe o
        WriteBytes = 1                           ; Number of byte to write to SPI module. 0 = 1 byte, counts from 0 to ?
        gosub NrfSPIWrite                        ; Send data to the Nrf Module.
        
        ; Writing to Address $03 
        NrfTxPckt[0] = WriteCmd + SetupAWAddr    ; Read/Write to the SETUP_AW REGISTER Address $03.
        NrfTxPckt[1] = 000001                 ; Data for EnAAAddr REGISTER Address $03. Address width is 3 bytes long.
        WriteBytes = 1                           ; Number of byte to write to SPI module. 0 = 1 byte, counts from 0 to ?
        gosub NrfSPIWrite                        ; Send data to the Nrf Module.
        
        ; Writing to Address $04 
        NrfTxPckt[0] = WriteCmd + SetupReTxAddr  ; Read/Write to the SETUP_RETR REGISTER Address $04.
        NrfTxPckt[1] = 010000                 ; Data for EnAAAddr REGISTER Address $04. AutoRetransmit set min and disabled.
        WriteBytes = 1                           ; Number of byte to write to SPI module. 0 = 1 byte, counts from 0 to ?
        gosub NrfSPIWrite                        ; Send data to the Nrf Module.
        
        ; Writing to Address $05 
        NrfTxPckt[0] = WriteCmd + SetupRfChAddr  ; Read/Write to the RF_CH REGISTER Address $05.
        NrfTxPckt[1] = 000010                 ; Data for EnAAAddr REGISTER Address $05. Rf Channel is set to default.
        WriteBytes = 1                           ; Number of byte to write to SPI module. 0 = 1 byte, counts from 0 to ?
        gosub NrfSPIWrite                        ; Send data to the Nrf Module.
        
        ; Writing to Address $06 
        NrfTxPckt[0] = WriteCmd + RfSetupAddr    ; Read/Write to the RF_SETUP REGISTER Address $06.
        NrfTxPckt[1] = 000110                 ; Data for EnAAAddr REGISTER Address $06. Data rate at 1Mbps, at 0dbm.
        WriteBytes = 1                           ; Number of byte to write to SPI module. 0 = 1 byte, counts from 0 to ?
        gosub NrfSPIWrite                        ; Send data to the Nrf Module.
    
        ; Writing to Address $0A 
        NrfTxPckt[0] = WriteCmd + RxPipe0Addr    ; Read/Write to the RX_ADDR_P0 REGISTER Address $0A. 
        NrfTxPckt[1] = 000001                 ; Data for EnAAAddr REGISTER Address $0A. Receive Address length is the same as address width.
                                                 ; Set to one, Current AW value will only use 1 byte instead of 3.
        WriteBytes = 1                           ; Number of byte to write to SPI module. 0 = 1 byte, counts from 0 to ?
        gosub NrfSPIWrite                        ; Send data to the Nrf Module.
        
    '    ; Writing to Address $0B 
    '    NrfTxPckt[0] = WriteCmd + RxPipe1Addr    ; Read/Write to the RX_ADDR_P1 Address $0B.
    '    NrfTxPckt[1] = 000000                 ; Data for EnAAAddr REGISTER Address $0B. Receive Address length is the same as address width.
    '                                             ; Set to one, Current AW value will only use 1 byte instead of 3.
    '    WriteBytes = 1                           ; Number of byte to write to SPI module. 0 = 1 byte, counts from 0 to ?
    '    gosub NrfSPIWrite                        ; Send data to the Nrf Module.
        
    '    ; Writing to Address $0C 
    '    NrfTxPckt[0] = WriteCmd + RxPipe2Addr    ; Read/Write to the RX_ADDR_P2 Address $0C.
    '    NrfTxPckt[1] = 000000                 ; Data for EnAAAddr REGISTER Address $0C. Receive Address length is the same as address width.
    '                                             ; Set to one, Current AW value will only use 1 byte instead of 3.
    '    WriteBytes = 1                           ; Number of byte to write to SPI module. 0 = 1 byte, counts from 0 to ?
    '    gosub NrfSPIWrite                        ; Send data to the Nrf Module.
        
    '    ; Writing to Address $0D 
    '    NrfTxPckt[0] = WriteCmd + RxPipe3Addr    ; Read/Write to the RX_ADDR_P3 Address $0D.
    '    NrfTxPckt[1] = 000000                 ; Data for EnAAAddr REGISTER Address $0D. Receive Address length is the same as address width.
    '                                             ; Set to one, Current AW value will only use 1 byte instead of 3.
    '    WriteBytes = 1                           ; Number of byte to write to SPI module. 0 = 1 byte, counts from 0 to ?
    '    gosub NrfSPIWrite                        ; Send data to the Nrf Module.
        
    '    ; Writing to Address $0E 
    '    NrfTxPckt[0] = WriteCmd + RxPipe4Addr    ; Read/Write to the RX_ADDR_P4 Address $0E.
    '    NrfTxPckt[1] = 000000                 ; Data for EnAAAddr REGISTER Address $0E. Receive Address length is the same as address width.
    '                                             ; Set to one, Current AW value will only use 1 byte instead of 3.
    '    WriteBytes = 1                           ; Number of byte to write to SPI module. 0 = 1 byte, counts from 0 to ?
    '    gosub NrfSPIWrite                        ; Send data to the Nrf Module.
        
    '    ; Writing to Address $0F 
    '    NrfTxPckt[0] = WriteCmd + RxPipe5Addr    ; Read/Write to the RX_ADDR_P5 Address $0F.
    '    NrfTxPckt[1] = 000000                 ; Data for EnAAAddr REGISTER Address $0F. Receive Address length is the same as address width.
    '                                             ; Set to one, Current AW value will only use 1 byte instead of 3.
    '    WriteBytes = 1                           ; Number of byte to write to SPI module. 0 = 1 byte, counts from 0 to ?
    '    gosub NrfSPIWrite                        ; Send data to the Nrf Module.
        
        ; Writing to Address $10 
        NrfTxPckt[0] = WriteCmd + TxADDRAddr     ; Read/Write to the TX_ADDR REGISTER Address $10.
        NrfTxPckt[1] = 000001                 ; Data for EnAAAddr REGISTER Address $10. Set to same as Receive Address.
        WriteBytes = 1                           ; Number of byte to write to SPI module. 0 = 1 byte, counts from 0 to ?
        gosub NrfSPIWrite                        ; Send data to the Nrf Module.
        
        ; Writing to Address $11 
        NrfTxPckt[0] = WriteCmd + RxPwPipe0Addr  ; Read/Write to the RX_PW_P0 REGISTER Address $11.
        NrfTxPckt[1] = 000101                 ; Data for EnAAAddr REGISTER Address $11. Set the number of bytes expected to be received.
        WriteBytes = 1                           ; Number of byte to write to SPI module. 0 = 1 byte, counts from 0 to ?
        gosub NrfSPIWrite                        ; Send data to the Nrf Module.
        
    '    ; Writing to Address $12 
    '    NrfTxPckt[0] = WriteCmd + RxPwPipe1Addr  ; Read/Write to the RX_PW_P1 REGISTER Address $12.
    '    NrfTxPckt[1] = 000000                 ; Data for EnAAAddr REGISTER Address $12. Set the number of bytes expected to be received.
    '    WriteBytes = 1                           ; Number of byte to write to SPI module. 0 = 1 byte, counts from 0 to ?
    '    gosub NrfSPIWrite                        ; Send data to the Nrf Module.
        
    '    ; Writing to Address $13 
    '    NrfTxPckt[0] = WriteCmd + RxPwPipe2Addr  ; Read/Write to the RX_PW_P2 REGISTER Address $13.
    '    NrfTxPckt[1] = 000000                 ; Data for EnAAAddr REGISTER Address $13. Set the number of bytes expected to be received.
    '    WriteBytes = 1                           ; Number of byte to write to SPI module. 0 = 1 byte, counts from 0 to ?
    '    gosub NrfSPIWrite                        ; Send data to the Nrf Module.
        
    '    ; Writing to Address $14 
    '    NrfTxPckt[0] = WriteCmd + RxPwPipe3Addr  ; Read/Write to the RX_PW_P3 REGISTER Address $14.
    '    NrfTxPckt[1] = 000000                 ; Data for EnAAAddr REGISTER Address $14. Set the number of bytes expected to be received.
    '    WriteBytes = 1                           ; Number of byte to write to SPI module. 0 = 1 byte, counts from 0 to ?
    '    gosub NrfSPIWrite                        ; Send data to the Nrf Module.
        
    '    ; Writing to Address $15 
    '    NrfTxPckt[0] = WriteCmd + RxPwPipe4Addr  ; Read/Write to the RX_PW_P4 REGISTER Address $15.
    '    NrfTxPckt[1] = 000000                 ; Data for EnAAAddr REGISTER Address $15. Set the number of bytes expected to be received.
    '    WriteBytes = 1                           ; Number of byte to write to SPI module. 0 = 1 byte, counts from 0 to ?
    '    gosub NrfSPIWrite                        ; Send data to the Nrf Module.
        
    '    ; Writing to Address $16 
    '    NrfTxPckt[0] = WriteCmd + RxPwPipe5Addr  ; Read/Write to the RX_PW_P5 REGISTER Address $16.
    '    NrfTxPckt[1] = 000000                 ; Data for EnAAAddr REGISTER Address $16. Set the number of bytes expected to be received.
    '    WriteBytes = 1                           ; Number of byte to write to SPI module. 0 = 1 byte, counts from 0 to ?
    '    gosub NrfSPIWrite                        ; Send data to the Nrf Module.
    
    
    '    ; Writing to Address $1C 
    '    NrfTxPckt[0] = WriteCmd + DynPldAddr     ; Read/Write to the DYNPD REGISTER Address $1C.
    '    NrfTxPckt[1] = 000000                 ; Data for EnAAAddr REGISTER Address $1C. Indicate that packets will be of different lengths for each data pipe.
    '    WriteBytes = 1                           ; Number of byte to write to SPI module. 0 = 1 byte, counts from 0 to ?
    '    gosub NrfSPIWrite                        ; Send data to the Nrf Module.
        
    '    ; Writing to Address $1D 
    '    NrfTxPckt[0] = WriteCmd + FeatureAddr    ; Read/Write to the FEATURE REGISTER Address $1D.
    '    NrfTxPckt[1] = 000000                 ; Data for EnAAAddr REGISTER Address $1D. Enable/Disable extra features.
    '    WriteBytes = 1                           ; Number of byte to write to SPI module. 0 = 1 byte, counts from 0 to ?
    '    gosub NrfSPIWrite                        ; Send data to the Nrf Module.
     
        gosub NrfRxMode
        NrfChipSel = 1                           ; Deselect the NRF Module.
        
        NrfChipEn = 1                            ; Enable the NRF Module.
    
    
    @   INT_ENABLE  TMR1_INT                     ; Enable Timer 1 interrupts. 
    
    ;*******************************************************************************
    Main:
    rx:
        if RxTxCounter = 10 then : RxTxCounter = 0 : gosub tx
        if NrfIRQ = 0 then
            NrfChipEn = 0                        ; Disable the NRF Module.
            gosub  NrfWriteStatus
            gosub NrfSPIReadPayload
            gosub FlushRxRegs
            NrfChipEn = 1                        ; Enable the NRF Module.
            hserout2  [str NrfRxPckt\6,13,10]    ; Send straight to USB             
        endif
        goto main
    
    
    ;*******************************************************************************
    tx:
        NrfChipEn = 0                            ; Disable the NRF Module.
        gosub NrfTxMode  
    
    
    LoadTXPckt: 
        NrfTxPckt[0] = WriteTxPld                ; Write Tx payload register address. Address $A0.                           
        NrfTxPckt[1] = "T"                       ; Data for WriteTxPld REGISTER.
        NrfTxPckt[2] = "E"                       ; Data for WriteTxPld REGISTER.
        NrfTxPckt[3] = "S"                       ; Data for WriteTxPld REGISTER.
        NrfTxPckt[4] = "T"                       ; Data for WriteTxPld REGISTER.
        NrfTxPckt[5] = "1"                       ; Data for WriteTxPld REGISTER.
        WriteBytes = 5                           ; Number of byte to write to SPI module. 0 = 1 byte, counts from 0 to ?        
    
    
        gosub NrfSPIWrite                        ; Send data to the Nrf Module.   
    
    
        NrfChipEn = 1                            ; Enable the NRF Module.
        pauseus 25                               ; Wait for for the module to complete transmission.
        NrfChipEn = 0                            ; Disable the NRF Module.
        pauseus 200                              ; Wait for IRQ to go low
        gosub  NrfWriteStatus                    ; Clear all flags in the module Status Register.
    
    
        gosub NrfRxMode
        NrfChipSel = 1                           ; Diselect the NRF Module.
        NrfChipEn = 1                            ; Enable the NRF Module.
        return      
    
    
    ;*******************************************************************************
    NrfWriteStatus:
        ; Writing to Address $07 
        NrfTxPckt[0] = WriteCmd + StatusAddr     ; Read/Write to the STATUS REGISTER Address $07.
        NrfTxPckt[1] = 110000                 ; Data for EnAAAddr REGISTER Address $07.
        WriteBytes = 1                           ; Number of byte to write to SPI module. 0 = 1 byte, counts from 0 to ?
        gosub NrfSPIWrite 
        return
    ;*******************************************************************************
    NrfTxMode:
        ; Writing to Address $00  
        NrfTxPckt[0] = WriteCmd + ConfigAddr     ; Read/Write to the CONFIG REGISTER Address $00.
        NrfTxPckt[1] = 000010                 ; Data for CONFIG REGISTER Address $00.
        WriteBytes = 1                           ; Number of byte to write to SPI module. 0 = 1 byte, counts from 0 to ?
        gosub NrfSPIWrite                        ; Send data to the Nrf Module.
        ; Writing to Address $07 
        NrfTxPckt[0] = WriteCmd + StatusAddr     ; Read/Write to the STATUS REGISTER Address $07.
        NrfTxPckt[1] = 010000                 ; Data for EnAAAddr REGISTER Address $07. Mask RXDataReceived and MAXRetransmit.
        WriteBytes = 1                           ; Number of byte to write to SPI module. 0 = 1 byte, counts from 0 to ?
        gosub NrfSPIWrite                        ; Send data to the Nrf Module.      
        ; Writing to Address $1D 
        NrfTxPckt[0] = FlushTx                   ; Write command to flush the TX Payload register.
        WriteBytes = 0                           ; Number of byte to write to SPI module. 0 = 1 byte, counts from 0 to ?   
        gosub NrfSPIWrite                        ; Send data to the Nrf Module.
        return
        
    ;******************************************************************************* 
    NrfRxMode:
        ; Writing to Address $00  
        NrfTxPckt[0] = WriteCmd + ConfigAddr     ; Read/Write to the CONFIG REGISTER Address $00.
        NrfTxPckt[1] = 110011                 ; Data for CONFIG REGISTER Address $00.
        WriteBytes = 1                           ; Number of byte to write to SPI module. 0 = 1 byte, counts from 0 to ?
        gosub NrfSPIWrite                        ; Send data to the Nrf Module.  
        ; Writing to Address $07 
        NrfTxPckt[0] = WriteCmd + StatusAddr     ; Read/Write to the STATUS REGISTER Address $07.
        NrfTxPckt[1] = 110000                 ; Data for EnAAAddr REGISTER Address $07. Mask TXDataSent and MAXRetransmit.
        WriteBytes = 1                           ; Number of byte to write to SPI module. 0 = 1 byte, counts from 0 to ?
        gosub NrfSPIWrite                        ; Send data to the Nrf Module.
        return
        
    ;******************************************************************************* 
    FlushRxRegs:
        ; Writing to Address $1D 
        NrfTxPckt[0] = Flushrx                   ; Write command to flush the TX Payload register.                         
        WriteBytes = 0                           ; Number of byte to write to SPI module. 0 = 1 byte, counts from 0 to ?
        gosub NrfSPIWrite                        ; Send data to the Nrf Module.
        return   
    
    
    ;*******************************************************************************
    SSP2IF_Check:
        while SSP2IF = 0                         ; Wait for the MSSP module to finish transmitting.
        wend
        SSP2IF = 0
        return
        
    ;*******************************************************************************
    NrfStatus: 
        while NrfMiso = 1                        ; Wait until module is ready to accept new data.
        wend                                     
        return
    
    
    ;*******************************************************************************  
    NrfSPIWrite:
        NrfChipSel = 0                           ; Select the NRF Module.
        for SPICounter = 0 to WriteBytes
            SSP2BUF = NrfTxPckt[SPICounter]      ; Write to the SPI buffer.
            gosub SSP2IF_Check                   ; Wait for the MSSP module to finish transmitting.
        Next SPICounter
        NrfChipSel = 1                           ; Deselect the NRF Module.
        return
        
    ;*******************************************************************************   
    NrfSPIReadPayload: 
        NrfChipSel = 0                           ; Select the NRF Module.    
        SSP2BUF = ReadRxPld                      ; Write to the SPI buffer.
        gosub SSP2IF_Check                       ; Wait for the MSSP module to finish transmitting.
        for SPICounter = 0 to 4                  ; Initialize counter to number of bytes being received.
            SSP2BUF = $FF                        ; Write No_Op byte to the SPI buffer.
            gosub SSP2IF_Check                   ; Wait for the MSSP module to finish transmitting.
            NrfRxPckt[SPICounter] = SSP2BUF      ; Copy the received byte from the SPI buffer.
        Next SPICounter 
        NrfChipSel = 1                           ; Deselect the NRF Module.
        return
        
    ;*******************************************************************************  
        end
    This article was originally published in forum thread: NRF24L01+ CODE Example for 1 to 1 data communication using same code on 2 PICs. started by csantex View original post