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 | Name | Usage or description |
BYTE | 0 | bnRFStatus | Most recently read value of nRF Register 7 (REG_7_STATUS) |
BYTE | 1 | bnRFPipe | Which nRF Pipe (used in PRX mode) was last received |
WORD | 2 | wnRFRxCount | Number of messages received |
WORD | 4 | wnRFTxCount | Number of messages transmitted |
BYTE | 6 | bnRFDebug | Individual debug enabling (BIT_NRFDDT_*) bits |
BYTE | 7 | bnRFID | Optional (individual or group) IDentity byte |
WORD | 8 | wnRFPollDelay | Polling timer delay (used with the next WORD) |
WORD | 10 | wnRFPollTimer | Polling timer starting time |
BYTE | 12 | bnRFuVarsBase | Base uVars.B[##] index for Rx values (from EE structure) |
BYTE | 13 | bnRFLastMID | Message ID byte from the most recent message received |
BYTE | 14 | bnRFTimeLimit | millisecond Transmit timer time limit (used with the next BYTE) |
BYTE | 15 | bnRFTimer | millisecond Transmit timer starting time |
ARRAY | 16 | anRFBuffer[32] | Beginning of the 32-byte Transmit Buffer, consisting of: |
BYTE | 16 | bnRFCount | Transmitted Byte #1: Transmit Message Byte Count |
BYTE | 17 | bnRFMsgID | Transmitted Byte #2: Transmit Message Sequence ID (0-255) |
ARRAY | 18 | anRFPayload[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): |
Bit | Name | Usage 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 the | 328P I/O | Port | --- Pin IDs on the --- |
nRF24L01+ chip | Direction | & Pin | Arduino | ATmega328P | Description |
CE | Output | B7 | 8 | 8 | Chip Enable |
CSN | Output | D4 | 4 | 2 | Chip Select |
SCK | Output | D5 | 5 | 9 | SPI Clock |
MOSI | Output | D6 | 6 | 10 | SPI Master Out, Slave In |
MISO | Input | D7 | 7 | 11 | SPI Master In, Slave Out |
IRQ | Input | D2 | 2 | 32 | Interrupt (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 Shown | nRF Register |
Offset | Data Size |
Set #1 | Set #2 |
Address | Mnemonic |
Description |
0 | 1 BYTE |
0x7C | 0x7D |
0 | CONFIG |
Interrupts, CRC, Power Up/Down, and PRX/PTX configuration bits |
1 | 1 BYTE |
0x3F | 0 |
1 | EN_AA |
Auto-acknowledgment enabling bits (0x3F = B00111111) |
2 | 1 BYTE |
0x3F | 0x3F |
2 | EN_RXADDR |
Receive addresses enabling bits (0x3F = B00111111) |
3 | 1 BYTE |
3 | 3 |
3 | SETUP_AW |
Address width; B00000011 (= 3) selects 5-byte addresses |
4 | 1 BYTE |
0x34 | 0x34 |
4 | SETUP_RETR |
Retries; B00110010 means 1 mSec interval, 2 retry limit |
5 | 1 BYTE |
0x4E | 0x4E |
5 | RF_CH |
RF channel 2,400 MHz + this value; 2.478 GHz (0x4E = 78) |
6 | 1 BYTE |
0x06 | 0x06 |
6 | RF_SETUP |
Data rate & RF output: B00000110 = 1 Mbps and 0dBm (= 1.0 mW) |
7 | 5 BYTEs |
"1Addr" | "1Addr" |
10 | RX_ADDR_P0 |
Receive address for Pipe 0; need not be ASCII text |
12 = 0x0C | 5 BYTEs |
"2Addr" | "2Addr" |
11 | RX_ADDR_P1 |
Receive address for Pipe 1; need not be ASCII text |
17 = 0x11 | BYTE |
0x33 = '3' | 0x33 = '3' |
12 | RX_ADDR_P2 |
Final byte of Pipe 2 Receive Address |
18 = 0x12 | BYTE |
0x34 = '4' | 0x34 = '4' |
13 | RX_ADDR_P3 |
Final byte of Pipe 3 Receive Address |
19 = 0x13 | BYTE |
0x35 = '5' | 0x35 = '5' |
14 | RX_ADDR_P4 |
Final byte of Pipe 4 Receive Address |
20 = 0x14 | BYTE |
0x36 = '6' | 0x36 = '6' |
15 | RX_ADDR_P5 |
Final byte of Pipe 5 Receive Address |
21 = 0x15 | 5 BYTEs |
"1Addr" | "1Addr" |
16 | TX_ADDR |
Full Transmit address for nRF24L01 in PTX mode |
26 = 0x1A | 1 BYTE |
0x3F | 0x3F |
28 | DYNPD |
Enable Dynamic Payload bits (0x3F = B00111111) |
27 = 0x1B | 1 BYTE |
7 | 7 |
29 | FEATURE |
Enable Dynamic Payload bits (0x07 = B00000111) |
28 = 0x1C | 1 BYTE |
0x88 | 0x88 |
bFlags_nRF * |
Initial bits: BIT_NRF_POWER_CMD and BIT_NRF_ENABLE |
29 = 0x1D | 1 WORD |
0x07D0 | 0x07D0 |
wnRFPollDelay * |
mSec between polling status transmissions (0x07D0 = 2,000) |
31 = 0x1F | 1 BYTE |
0 | 0 |
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