The Nordic Semiconductor® nRF24L01+ radio commands

The list of nRF24L01 commands supported:
"N"         alone reads and displays each of the 26 nRF24L01 Register values
"N*"        loads the nRF24L01 configuration (all 26 registers) from EEptrNRF24L01Cfg
"N**"       same as above, but also load bFlags_nRF from config byte EEbNR_GPIOR0
"N+"        enables nRF24L01 autoprocessing (sets BIT_NRF_ENABLE); "N-" clears it
"N ##"      loads an nRF configuration from a specific EEPROM address
"N ## ?"    dumps the value of a single nRF register ("N ? ##" works as well)
"N ## = ##" sets a specific register to the value specified
"NA+"       sends W_TX_PAYLOAD       commands, when transmitting
"NA-"       sends W_TX_PAYLOAD_NOACK commands, when transmitting
"NC"        clears (flushes) both the nRF Transmit and Receive buffers; resets RX_DR, TX_DS, MAX_RT
"ND+"       enables the default nRF debugging output flags, which are these 4:
              BIT_NRFDDT_CLRERRS, BIT_NRFDDT_RX, BIT_NRFDDT_TX, and BIT_NRFDDT_TX_COPY
"ND-"       clears ALL nRF debugging flags, not only the 4 default flags above
"ND7+"      sets BIT_NRFDDT_R7_TXDS in bnRFDebug; "ND7-" clears it (also "NR+" & "NR-")
"NDC+"      sets BIT_NRFDDT_TX_COPY in bnRFDebug; "NDC-" clears it
"NDD+"      sets BIT_NRFDDT_DETAILS in bnRFDebug; "NDD-" clears it
"NDE+"      sets BIT_NRFDDT_CLRERRS in bnRFDebug; "NDE-" clears it
"NDN+"      sets BIT_NRFDDT_RX_RAW  in bnRFDebug; "NDN-" clears it (also "NN+" & "NN-")
"NDP+"      sets BIT_NRFDDT_POLLTIC in bnRFDebug; "NDP-" clears it (also "NDQ+" & "NDQ-")
"NDR+"      sets BIT_NRFDDT_RX      in bnRFDebug; "NDR-" clears it
"NDT+"      sets BIT_NRFDDT_TX      in bnRFDebug; "NDT-" clears it
"ND = ##    sets the bnRFDebug byte to the value (i.e., bitmask) specified
"NE+"       enables echoing of COM1 to NRF (sets BIT_NRF_ECHO_COM1); "NE-" clears it
"NF"        flush the nRF24L01 chip's transmit buffer (i.e., means purge it, not transmit it)
"NFR"       flush the nRF24L01 chip's receive  buffer (again, purge it)
"NI"        initialize the nRF24L01 chip (set from the default configuration in EEptrNRF24L01Cfg)
"NJ+"       enables IRQ0 interrupt vector to a user-supplied routine; "NJ- clears it
"NL = ###"  set the timer limit (mSec to wait after last RxByte until Tx)
"NP+"       sets PWR_UP in nRF REG_0_CONFIG - powers the chip up; "NP-" powers it down
"NQ+ [= ### [##]]"   enable polling option(s)
"NU+"       enable BIT_NRF_UPPERCASE in GPIOR0 to convert Received message to Uppercase; "NU-" clears it
"N 'text'"  place the text in 'text' in the nRF transmit buffer; can include spaces
"N>"        transmit all enbuffered bytes now (bypass the bNRFTimer)
"N> 'text'" enbuffer the text and transmit it immediately, without the delay
Notes:
  No distinction is made between uppercase and lowercase commands.
  'text' is string up to 30 characters   ## is a numeric value, in either decimal or hexadecimal format.
  The "N 'text'" and "N> 'text' command accepts either double quote or single quote text delimiters.
  There space between "N 'text'" and "N> 'text'" is not required.

The 48-byte nRF Data Structure in SRAM:
Type Offset NameUsage or description
BYTE0bnRFStatusMost recently read value of nRF Register 7 (REG_7_STATUS)
BYTE1bnRFPipeWhich nRF Pipe (used in PRX mode) was last received
WORD2wnRFRxCountNumber of messages received
WORD4wnRFTxCountNumber of messages transmitted
BYTE6bnRFDebugIndividual debug enabling (BIT_NRFDDT_*) bits
BYTE7bnRFIDOptional (individual or group) IDentity byte
WORD8wnRFPollDelayPolling timer delay (used with the next WORD)
WORD10wnRFPollTimerPolling timer starting time
BYTE12bnRFuVarsBaseBase uVars.B[##] index for Rx values (from EE structure)
BYTE13bnRFLastMIDMessage ID byte from the most recent message received
BYTE14bnRFTimeLimitmillisecond Transmit timer time limit (used with the next BYTE)
BYTE15bnRFTimermillisecond Transmit timer starting time
ARRAY16anRFBuffer[32]Beginning of the 32-byte Transmit Buffer, consisting of:
BYTE16bnRFCount   Transmitted Byte #1: Transmit Message Byte Count
BYTE17bnRFMsgID   Transmitted Byte #2: Transmit Message Sequence ID (0-255)
ARRAY18anRFPayload[30]     Transmitted Bytes #3 to (up to) #32 (may send less than 32)
Graphically, the structure looks like this:
     +--------+--------+--------+--------+--------+--------+--------+--------+
 +0  | Status |  Pipe  |  Receive Count  | Transmit Count  |  Debug |   ID   |
     +--------+--------+--------+--------+--------+--------+--------+--------+
 +8  |  Polling Delay  |  Polling Timer  | uVarsB | LastMID| TLimit | LTimer |
     +--------+--------+--------+--------+--------+--------+--------+--------+
 +16 |  Count |   ID   |   Payload ...                                       |
     +--------+--------+--------+--------+--------+--------+--------+--------+
 +24 |                                                                       |
     +--------+--------+--------+--------+--------+--------+--------+--------+
 +32 |                                                                       |
     +--------+--------+--------+--------+--------+--------+--------+--------+
 +40 |                                       ... Payload              Last1  |
     +--------+--------+--------+--------+--------+--------+--------+--------+
>DN+    ; To display the contents of the nRF structure:
SRAM contents:
0200:  0E 00 00 00 02 00 D1 00-D0 07 00 00 00 00 2A 00  ..............*.
0210:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
0220:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
>                                                                               
The definitions of the bits in bnRFDebug (the BYTE at offset 6 above):
BitNameUsage or description
  0  BIT_NRFDDT_CLRERRS Display nRF_ClearErrors() details
  1   BIT_NRFDDT_DETAILS Show nRF block details in nRF_*Debug() subroutines
  2   BIT_NRFDDT_POLLTIC Show when a timed polling message is being transmitted()
  3   BIT_NRFDDT_R7_TXDS Debug feedback in nRF_ClearBlockages()
  4   BIT_NRFDDT_RX Display the details of all received messages
  5   BIT_NRFDDT_RX_RAW Display receive buffer in raw format for all received messages
  6   BIT_NRFDDT_TX Display the details of all transmitted messages
  7   BIT_NRFDDT_TX_COPY   On each transmission, copy the 48-byte nRF structure to high memory
(0x600 on the 328P) after shifting the prior 5 blocks up 48 bytes

There are many commands and options for the nRF radio. After connecting the breakout board, start by checking the contents of the nRF24L01+ chip's Registers, to verify that it is connected correctly. The "N" command alone is used to do that.
>N  ; Check the Registers
0x00 (FF) -> 0xFF = B11111111
0x01 (FF) -> 0xFF = B11111111
0x02 (FF) -> 0xFF = B11111111
0x03 (FF) -> 0xFF = B11111111
0x04 (FF) -> 0xFF = B11111111
0x05 (FF) -> 0xFF = B11111111
0x06 (FF) -> 0xFF = B11111111
0x07 (FF) -> 0xFF = B11111111
0x08 (FF) -> 0xFF = B11111111
0x09 (FF) -> 0xFF = B11111111
0x0A (FF) -> 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
0x0B (FF) -> 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
0x0C (FF) -> 0xFF = B11111111
0x0D (FF) -> 0xFF = B11111111
0x0E (FF) -> 0xFF = B11111111
0x0F (FF) -> 0xFF = B11111111
0x10 (FF) -> 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
0x11 (FF) -> 0xFF = B11111111
0x12 (FF) -> 0xFF = B11111111
0x13 (FF) -> 0xFF = B11111111
0x14 (FF) -> 0xFF = B11111111
0x15 (FF) -> 0xFF = B11111111
0x16 (FF) -> 0xFF = B11111111
0x17 (FF) -> 0xFF = B11111111
0x1C (FF) -> 0xFF = B11111111
0x1D (FF) -> 0xFF = B11111111
>                                                                               
The command example above shows nRF chip's Registers were not read. Assuming that an nRF24L01+ breakout board (e.g., like this one, made by SparkFun®) is being used, the six (6) pins between Vcc and Ground are those shown below, along with where each of them should connect to the 328P microcontroller.

Pin name on the328P I/OPort--- Pin IDs on the ---
nRF24L01+ chip Direction & Pin Arduino ATmega328P  Description
CEOutputB7 88Chip Enable
CSNOutputD4 42Chip Select
SCKOutputD5 59SPI Clock
MOSIOutputD6610SPI Master Out, Slave In
MISOInputD7 711SPI Master In, Slave Out
IRQInputD2 232Interrupt (active LOW; IRQ0)

Once connected, load one of the default nRF24L01 configurations. Both a PTX (Primary Transmitter) and PRX (Primary Receiver) default configuration are shown below. Each occupies 32 bytes; the 16-byte comments preceeding each data set are helpful, but not required.
>DE+ 0x50 0x30
EEPROM contents:
0050:  6E 52 46 20 50 54 58 20-63 6F 6E 66 69 67 3A 00  nRF PTX config:.
0060:  7C 3F 3F 03 34 4E 06 31-41 64 64 72 32 41 64 64  |??.4N.1Addr2Add
0070:  72 33 34 35 36 31 41 64-64 72 3F 07 88 D0 07 00  r34561Addr?.....
>DE+ 0x80 0x30
EEPROM contents:
0080:  6E 52 46 20 50 52 58 20-63 6F 6E 66 69 67 3A 00  nRF PRX config:.
0090:  7D 00 3F 03 34 4E 06 31-41 64 64 72 32 41 64 64  }.?.4N.1Addr2Add
00A0:  72 33 34 35 36 31 41 64-64 72 3F 07 88 D0 07 00  r34561Addr?.....
>                                                                               
The meanings of the values shown in each configuration above:
Value ShownnRF Register
Offset  Data Size   Set #1  Set #2   Address  Mnemonic   Description
01 BYTE 0x7C0x7D 0CONFIG Interrupts, CRC, Power Up/Down, and PRX/PTX configuration bits
11 BYTE 0x3F0 1EN_AA Auto-acknowledgment enabling bits (0x3F = B00111111)
21 BYTE 0x3F0x3F 2EN_RXADDR Receive addresses enabling bits (0x3F = B00111111)
31 BYTE 33 3SETUP_AW Address width; B00000011 (= 3) selects 5-byte addresses
41 BYTE 0x340x34 4SETUP_RETR Retries; B00110010 means 1 mSec interval, 2 retry limit
51 BYTE 0x4E0x4E 5RF_CH RF channel 2,400 MHz + this value; 2.478 GHz (0x4E = 78)
61 BYTE 0x060x06 6RF_SETUP Data rate & RF output: B00000110 = 1 Mbps and 0dBm (= 1.0 mW)
75 BYTEs "1Addr""1Addr" 10  RX_ADDR_P0   Receive address for Pipe 0; need not be ASCII text
12 = 0x0C5 BYTEs "2Addr""2Addr" 11RX_ADDR_P1 Receive address for Pipe 1; need not be ASCII text
17 = 0x11BYTE 0x33 = '3'0x33 = '3' 12RX_ADDR_P2 Final byte of Pipe 2 Receive Address
18 = 0x12BYTE 0x34 = '4'0x34 = '4' 13RX_ADDR_P3 Final byte of Pipe 3 Receive Address
19 = 0x13BYTE 0x35 = '5'0x35 = '5' 14RX_ADDR_P4 Final byte of Pipe 4 Receive Address
20 = 0x14BYTE 0x36 = '6'0x36 = '6' 15RX_ADDR_P5 Final byte of Pipe 5 Receive Address
21 = 0x155 BYTEs "1Addr""1Addr" 16TX_ADDR Full Transmit address for nRF24L01 in PTX mode
26 = 0x1A1 BYTE 0x3F0x3F 28DYNPD Enable Dynamic Payload bits (0x3F = B00111111)
27 = 0x1B1 BYTE 77 29FEATURE Enable Dynamic Payload bits (0x07 = B00000111)
28 = 0x1C1 BYTE 0x880x88 bFlags_nRF * Initial bits: BIT_NRF_POWER_CMD and BIT_NRF_ENABLE
29 = 0x1D1 WORD 0x07D00x07D0 wnRFPollDelay * mSec between polling status transmissions (0x07D0 = 2,000)
31 = 0x1F1 BYTE 00 bnRFuVarsBase * Base uVars.B[##] index for Received values
* These are not nRF24L01+ Registers but are loaded into the corresponding 48-byte nRF Data Structure elements in SRAM.

For futher details about the first 28 BYTEs of the configurations, which are loaded into the nRF24L01+ radio microchip from EEPROM, please refer to the Nordic Semiconductor ® nRF24L01+ Product Specification, version 1.0, dated September, 2008.

To load the default 32-byte configuration from EEPROM into the nRF24L01 radio chip, use the "N*" command. To also load the default bFlags_nRF BYTE, use the "N**" command. Since the bFlags_nRF BYTE contains the BIT_NRF_ENABLE bit (same as using "N+"), a single "N**" command can both configure the radio and put it online. Use "ND+" to enabled the default debugging options.

To load a configuration from a specific EEPROM address, use "N address", as shown in the example below. "N*" and "N address" do not change the nRF debugging bits, so they can be set and the configuration changed or reloaded while still maintaining the nRF debugging environment.
>N 0x60  ; Load the configuration beginning at EEPROM address 0x60
>N       ; Display the contents of all 26 nRF24L01 Registers
0x00 (0E) -> 0x7E = B01111110
0x01 (0E) -> 0x3F = B00111111
0x02 (0E) -> 0x3F = B00111111
0x03 (0E) -> 0x03 = B00000011
0x04 (0E) -> 0x34 = B00110100
0x05 (0E) -> 0x4E = B01001110
0x06 (0E) -> 0x06 = B00000110
0x07 (0E) -> 0x0E = B00001110
0x08 (0E) -> 0x00 = B00000000
0x09 (0E) -> 0x00 = B00000000
0x0A (0E) -> 0x31, 0x44, 0x65, 0x6D, 0x6F
0x0B (0E) -> 0x32, 0x44, 0x65, 0x6D, 0x6F
0x0C (0E) -> 0x33 = B00110011
0x0D (0E) -> 0x34 = B00110100
0x0E (0E) -> 0x35 = B00110101
0x0F (0E) -> 0x36 = B00110110
0x10 (0E) -> 0x31, 0x44, 0x65, 0x6D, 0x6F
0x11 (0E) -> 0x00 = B00000000
0x12 (0E) -> 0x00 = B00000000
0x13 (0E) -> 0x00 = B00000000
0x14 (0E) -> 0x00 = B00000000
0x15 (0E) -> 0x00 = B00000000
0x16 (0E) -> 0x00 = B00000000
0x17 (0E) -> 0x11 = B00010001
0x1C (0E) -> 0x3F = B00111111
0x1D (0E) -> 0x07 = B00000111
>                                                                               
If the BIT_NRFDDT_TX_COPY bit (set with "NDC+" and cleared with "NDC-") is set (or TRUE), then just prior to loading the nRF24L01 with the bytes to be transmitted, MIRTOS 1) moves the contents of SRAM at addresses 0x600 to 0x6BF upward 48 bytes to 0x630 to 0x6EF then 2) copies the entire 48-byte nRF Data Structure to 0x600 to 0x62F. That means that when enabled, the data structures for most recent five (5) messages transmitted from a node are saved for review, with the oldest one at the higher memory address. Any data in addresses 0x6C0 through 0x6EF will be overwritten.

This feature allows the details of each nRF message transmitted to be examined. It could be left enabled, since that area of the HEAP is out of the way of most stack usage. If the WS2812 LEDs are being used, however, and more than about 240 pixels are configured, then depending on how many uVars.B[##] are configured, there may be a conflict. It is preferable to disable this feature if message debugging is complete.
>ND+     ; Enable the default debugging options
>DS+ 0x600 256  ; Location of the "High memory" block, now empty
SRAM contents:
0600:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
0610:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
0620:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
0630:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
0640:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
0650:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
0660:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
0670:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
0680:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
0690:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
06A0:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
06B0:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
06C0:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
06D0:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
06E0:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
06F0:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
>N "This is test message #1"
>nRF Tx [26, 0xB0]: 25, 1, 'This is test message #1'
>DS+ 0x600 256
SRAM contents:
0600:  0E 00 00 00 01 00 D1 00-D0 07 00 00 00 00 2A B0  ..............*.
0610:  19 01 54 68 69 73 20 69-73 20 74 65 73 74 20 6D  ..This is test m
0620:  65 73 73 61 67 65 20 23-31 00 00 00 00 00 00 00  essage #1.......
0630:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
0640:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
0650:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
0660:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
0670:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
0680:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
0690:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
06A0:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
06B0:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
06C0:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
06D0:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
06E0:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
06F0:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
>N "This is test message #2"
>nRF Tx [26, 0xB0]: 25, 2, 'This is test message #2'
>DS+ 0x600 256
SRAM contents:
0600:  0E 00 00 00 02 00 D1 00-D0 07 00 00 00 00 2A B0  ..............*.
0610:  19 02 54 68 69 73 20 69-73 20 74 65 73 74 20 6D  ..This is test m
0620:  65 73 73 61 67 65 20 23-32 00 00 00 00 00 00 00  essage #2.......
0630:  0E 00 00 00 01 00 D1 00-D0 07 00 00 00 00 2A B0  ..............*.
0640:  19 01 54 68 69 73 20 69-73 20 74 65 73 74 20 6D  ..This is test m
0650:  65 73 73 61 67 65 20 23-31 00 00 00 00 00 00 00  essage #1.......
0660:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
0670:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
0680:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
0690:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
06A0:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
06B0:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
06C0:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
06D0:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
06E0:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
06F0:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
>                                                                               
User-Supplied Interrupt Service Routine:
   By default, the nRF24L01 interrupt, ISR0, is disabled. The Operating System uses polling to determine if the nRF needs servicing. The "NJ+" command enables ISR0, but first be sure there is an interrupt service routine in place or the first interrupt will cause the system to appear to hang up (and the watchdog likely won't timeout.) In actuality, the ISR is being called repeatedly and, with no way to clear it, all other processes will occur very, VERY slowly. Either pull the ISR line from the nRF breakout board (or the board itself) to stop the interrupts or power down the microcontroller.
DO NOT call a print routine inside any interrupt handler! Since interrupts are disabled, the serial output buffer cannot be cleared. Printing is the only blocking function, so it will very likely hang the microcontroller. There are at least two ways to debug interrupt logic, however. The first is to log information to a block of memory and view it after returning from the ISR. It is shown in this example code. The other way is by using LEDs to display some aspect(s) of the ISR logic. Since there are only a few LEDs available, consider displaying a block of values using the WS2812 command. See the example of how this method can be used.
Here is a small example, which simply disables the interrupt. Since this ISR can be used for many unallocated interrupt sources, it must first determine which one caused the interrupt.
DisableISR:
   CPI     R26, '0'             ; Only want to intercept the NRF IRQ
   BRNE    ADisableISR_Exit     ; Only the FLAGs are changed (saved by the caller)

   SBI     PORTC, PORTC0        ; LED #1 (an possibly RELAY #1) feedback
   CBI     EIMSK, INT0          ; Clear the bits which enable the interrupt and let
   CBI     bFlags_nRF, BIT_NRF_ENABLE_IRQ    ;  the sleep routine know to use it

DebugISR_Exit:
   RET