nRF_SPI_Command

Purpose: Output one (1) command BYTE and option sequence (of up to 32 bytes) out to the Nordic chip's SPI port.
Assumes:   This does NOT use the ATmega328P's SPI port, but uses the PORTs and PINs shown in the Notes section below.
Passed: R24 BYTE bOpCode the nRF24L01+ Command Byte to send, i.e., one of the eleven (11) constants beginning with NRF_CMD_ in nRF24L01.Def.
R22 BYTE bReplyCount   the number of reply BYTEs to send; 1 to 33 (Opcode + data)
R21:R20   BYTE * bPtrDest   pointer to the destination buffer.
Returns: R25 BYTE bReplyBYTE1   the first (or possibly only) BYTE of the reply; it is the same as the first BYTE in the buffer
R24 BYTE bStatus the REG_7_STATUS value read while bit-shifting the Command BYTE out
Alters: R23, R24, R25 the FLAGs (SREG), and the destination buffer
Example:  
.ORG 0x2000
   ADIW    R26, 0               ; If there is no command tail, there is nothing
   BREQ    ALocal_Ret           ;  to do

   MOVW    R24, R26             ; StackAlloc() changes R0, R27:R26, and R31:R30
   CALL    AStackAlloc50        ; Setup a small temporary buffer
   MOVW    R26, R24             ; Restore the command line tail pointer passed

   MOVW    R24, R30             ; Copy the buffer pointer returned to R25:R24
   LDI     R22, 0xFF            ; The value each BYTE will receive
   LDI     R21, 0               ; The number of BYTEs to initialize = 50
   LDI     R20, 50              ; Initialize the stack-based buffer
   CALL    Ameminit             ; The meminit() call preserves ALL Registers

   MOVW    R24, R26             ; Restore the command line tail pointer passed
   CALL    AParseValue          ; Always returns a ULONG in R25:R24:R23:R22
   SBRS    R21, BIT_PV_VALID    ; Skip if there was an extractable value
   RJMP    ALocal_Exit          ; Exit since no Command BYTE was specified

   ADIW    R26, 0               ; If there is nothing left to parse in the
   BREQ    ALocal_Exit          ;  remaining command tail, exit now
   MOVW    R24, R26             ; Point to that buffer to setup ParseValue()
   PUSH    R22                  ; Save the nRF Command BYTE parsed above
   CALL    AParseValue          ; Note that ParseValue() preserves R31:R30
   POP     R24                  ; Place the nRF Command BYTE in R24, and that
   SBRS    R21, BIT_PV_VALID    ;  leaves the second BYTE parsed in R22
   RJMP    ALocal_Exit          ; Exit if no Request Count BYTE was specified
   CPI     R22, 0               ; If the request is for 0 bytes, it will be
   BRNE    AGo                  ;  discarded, so change a request of 0 to 1
   INC     R22                  ; It will also discard > 33, by the way

Go:MOVW    R20, R30             ; Set the destination pointer to be the same
   CALL    ADumpRegisters       ;  stack-based buffer allocated; optional
   CALL    AnRF_SPI_Command     ;  Register display both before and after the
   CALL    ADumpRegisters       ;  nRF_SPI_Command() call; preserves R31:R30

   MOVW    R24, R30             ; Point R25:R24 at the starting address
   CPI     R22, 2               ; nRF_SPI_Command() leaves R22 unchanged
   BRLO    AOK                  ; To set the ending address in R31:R30, add
   DEC     R22                  ;  the starting address to the number of
OK:ADD     R30, R22             ;  BYTEs, less 1, noting that DumpRegisters
   ADC     R31, R1              ;  will discard any request with the same
   MOVW    R22, R30             ;  starting and ending addresses -> to R23:R22
   
   LDI     R20, 'R'             ; Specify SRAM (anything but 'E', 'F' or 'P')
   LDI     R18, 1 << BIT_DM_FOREGROUND   ; Output the data before the prompt
   CALL    ADumpMemory          ; Display the block of SRAM written

Local_Exit:
   CALL    AStackFree50         ; Delete the temp buffer & restore stack
Local_Ret:
   RET
Test it:
m>N   ; Display all of the nRF24L01 Registers' values
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) -> 0x32, 0x44, 0x65, 0x6D, 0x6F
0x0B (0E) -> 0x31, 0x44, 0x65, 0x6D, 0x6F
0x0C (0E) -> 0x33 = B00110011
0x0D (0E) -> 0x34 = B00110100
0x0E (0E) -> 0x35 = B00110101
0x0F (0E) -> 0x36 = B00110110
0x10 (0E) -> 0x32, 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
m>@ 8192 0 1     ; Can request 1 but DumpRegs() needs at least 2 BYTEs
SRAM contents:
08C0:           7E FF                                      ~.
m>@ 8192 0 2
SRAM contents:
08C0:           7E 7E                                      ~~
m>@ 8192 10 5
SRAM contents:
08C0:           32 44 65 6D 6F                             2Demo
m>@ 8192 0xE1 1     ; This is the NRF_CMD_FLUSH_TX command
SRAM contents:
08C0:           00 FF                                      ..
m>@ 8192 0xE1 0     ; The same command (0 request changed to 1)
SRAM contents:
08C0:           00 FF                                      ..
m>@ 0x2000 0xE2 1   ; This is the NRF_CMD_FLUSH_RX command
SRAM contents:
08C0:           00 FF                                      ..
m>@ 0x2000 0xFF 1   ; After turning on the DumpRegisters() debug output:

 10   32   54   76   98  1110 1312 1514 1716 1918 2120 2322 2524 2726 2928 3130
---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
0000 0206 0931 FF28-0004 0000 0000 4000-0021 007E 400F 3020-940F 0230 0280 1780
0080 0206 0931 FF28-0004 0000 0000 4000-0021 0000 08C3 0001-00FF 0000 0280 08C3
0080 0206 0931 FF28-0004 0000 0000 4000-0021 0000 08C3 9201-000E 0000 0280 08C3
SRAM contents:
08C0:           00 FF                                      ..
m>  ; Note the values returned in R25 and R24 above and below
m>@ 0x2000 10 5

 10   32   54   76   98  1110 1312 1514 1716 1918 2120 2322 2524 2726 2928 3130
---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
0000 010C 0950 FF28-0004 0000 0000 4000-0021 007E 400D 3020-940F 0230 0280 1780
0080 010C 0950 FF28-0004 0000 0000 4000-0021 0000 08C3 0005-000A 0000 0280 08C3
0080 010C 0950 FF28-0004 0000 0000 4000-0021 0000 08C3 1205-320E 0000 0280 08C3
SRAM contents:
08C0:           32 44 65 6D 6F                             2Demo
>                                                                                           
Notes:
                                                       +----+
                       These are the layouts for       | *1 | Vcc
     +--------+         the Nordic nRF24L01+ radio     | *2 | CE
 Gnd | *1  2* | Vcc     connections on the SSG         | *3 | CSN
  CE | *3  4* | CSN     circuit boards which have      | *4 | SCK
 SCK | *5  6* | MOSI    them.  They are shown          | *5 | MOSI
MISO | *7  8* | IRQ0    looking down on them from      | *6 | MISO
     +--------+         above.  The corresponding      | *7 | IRQ0
       nRF#2            ATmega328P pins used are       | *8 | Gnd
                        documented below.              +----+
                                                        nRF#1

        Port   I/O                   Arduino  328P
Label   & Pin  Dir  Variable name      Pin    Pin   Description
-----  ------  ---  ---------------  ------- -----  ------------------------
nCE    PORTB7  Out  PIN_NORDIC_CE       8      8    Chip Enable
nCSN   PORTD4  Out  PIN_NORDIC_CSN      4      2    Chip Select
nSCK   PORTD5  Out  PIN_NORDIC_SCK      5      9    SPI Clock
nMOSI  PORTD6  Out  PIN_NORDIC_MOSI     6     10    SPI Master Out, Slave In
nMISO  PORTD7   In  PIN_NORDIC_MISO     7     11    SPI Master In, Slave Out
nIRQ   PORTD2   In  PIN_NORDIC_IRQ      2     32    Interrupt (active LOW)
nIRQ0  PORTD2   In  PIN_IRQ0            2     32    Nordic Radio IRQ
There are at least three reasons why the choice to "bit-bang" the SPI command using the PORTs and PINs above rather than use the ATmega328P's SPI port. First, the nRF protocol is BIT-shifting the REG_7_STATUS value in while at the same time that the Command BYTE is being BIT-shifted out. That would not be done with the standard SPI protocol. Second, it leaves the actual ATmega328P SPI port available for other uses. Third, the system is simple enough and the transaction times fast enough (in the 27 to 28 microSeconds timeframe) that it is simpler just to wait for the response rather than deal with the task synchronization and sequencing issues that are the alternative. Why not simplify things?
All nRF24L01+ Registers are 1-BYTE wide except REG_10_RX_ADDR_P0, REG_11_RX_ADDR_P1, and REG_16_TX_ADDR, which are each 5-BYTE wide Registers.
For more information about the nRF24L01+ radio microchip itself, please refer to the Nordic Semiconductor ® nRF24L01+ Product Specification, version 1.0, dated September, 2008.
The supported SPI commands are the eleven (11) listed in Table 20. Command set for the nRF24L01+ SPI, on page 51 of the file listed and linked above.
Dropin: 
(setup
code)
;   Setup for the NRF_SPI_Command() call:
; Passed:      R24 BYTE   bOpCode     NRF_CMD_* opcode to send as first BYTE
;              R22 BYTE   bReplyCount number of reply BYTEs to request (1-33)
;          R21:R24 BYTE * bPtrDest    pointer to the target buffer in SRAM
; Returns:     R25 BYTE   bReplyBYTE1 same as first byte placed in the buffer
;              R24 BYTE   bStatus     the REG_7_BYTE read while writing bOpCode
; Alters:  R23, R24, R25, the FLAGs, and the destination data buffer
Also see:  The nRF_SPI_Command System Function and the Nordic nRF24L01+ radio script commands.