NRF24L01+ Driver : Part 3 : Functional Description


Now it is time to understand the required steps to get the NRF24L01+ transmitting and receiving. After this we will move on to finally writing some code. 

If you are not satisfied with these explanations feels free to read APENDIX A and relevant sections in the datasheet HERE 

Packet Format:

Before I go into details about transmission and reception it is important to understand the packet format. Since this will affect your ultimate throughput and power consumption, because the more bits you send the more time is spent transmitting, thus using power. And lets face it these are super fast transmitters.

The good thing is that packet formatting/ assembling and disassembling are all things the NRF does on its own with no additional lines of code on our side. The folks at Nordic called this packet formatting Enhanced ShockBurst™ and it looks like the image below. It is recommended to always operate in Enhanced Shockburst mode because it takes care of some critical things like not keeping the transmitter in transmit for too long.

According to the datasheet, and my beautifully designed image above, the packet format consists of several fields. Also note that the entire packet of data is transmitted MSB , most significant byte first, and each byte is transmitted LSB least significant bit first. This might sound weird or confusing but do not worry the hardware inside the NRF takes care of all of that behind the scenes for you. 

Preamble

Preamble is nothing more then a sequence of 1s and 0s to synchronize the receiver's demodulator to the incoming stream. It is only one byte long, if the first bit in the address is a 1 then the preamble is 10101010, otherwise it is 01010101.

Address

This section is the address corresponding to the pipe in the receiver you are sending it to. The address field is configurable to be 3 , 4 or 5 bytes long. You might be wondering then how can this be if the RX_ADDR_P# registers are only 1 byte long. That is because only 1 byte of the address of those pipes is editable , the remaining bytes are fixed to match the bytes that are in Pipe 1.


Packet Control

The packet control section has 3 sections within itself.
  1. Payload length is a 6 bit field that tells the receiver the length of the incoming payload This field however is only used when dynamic payload length is enabled. Otherwise the value in RX_PW_P# register is the width of the payload.
  2. PID is the packet identification field. It is used to tell the receiver whether this packet is new or a re-transmitted packet. That way the receiver knows not to present a re-transmitted packet to the mcu if it has already presented this same packet before. THAT DOES NOT MEAN YOU CANNOT SEND THE SAME DATA TWICE, this "re-transmit" is more like an error or somehow the ACK was not received by the transmitter and now its re-transmitting the same packet. 
  3. NO_ACK this is a bit that tells the receiver that no auto ACK should be used for this packet.
The packet format is assembled in the hardware all depending on your settings in the registers, formatting/assembling and disassembling the packet is nothing you have to worry about in your code. 

**Every time you start an SPI communication instance you must drive low the CSN pin, this is the slave select line and makes the NRF start listening in its SPI lines. I will remind you of this in the code**

Transmitting

In order for the NRF to properly transmit your data certain steps must be taken in a specific order. The following steps will use Enhanced Shockburst mode because it is the best way to go.

NOTE: According to the datasheet there is a 100ms ramp up time after the chip is given power. So if you have a fast mcu do not try to start transmitting right away. Let the voltage reach optimum levels and let the crystal oscillator stabilize. A small delay anywhere before initializing the chip should be fine. You will also use small delays in another section so have a delay function handy, preferably something with 100us resolution , any mcu above 10MHz can give you a 100us delay functionality, maybe not exact but close enough.

Transmitting

Setup:

  1. The CE pin must start out LOW, because a HIGH to LOW transition is what causes the transmission to start. So before anything is done make sure the CE pin is LOW alos the CE pin should not be held high for too long. but the NRF takes care of that in Enhanced Shockburst mode.
  2. Next you want to power up the chip internally by setting the PWR_UP bit in the CONFIG register
  3. Clear (0) the PRIM_RX bit in the CONFIG register to use the NRF as a transmitter
  4. Set CRC encoding scheme 1 byte or 2 bytes , by setting or clearing the CRCO bit in the CONFIG register
  5. Enable the CRC itself by setting the EN_CRC bit in the CONFIG register, you can skip this since enabling auto ACK on any pipe will force this bit high anyways.
  6. Set the interrupts desired in the CONFIG register, clearing them (0) means they will be active.
  7. Set address width in the SETUP_AW 
  8. Setup wait time in between re-transmissions after a failed transmission 
  9. Setup max number of re-transmits
  10. As a safety measure clear interrupt flags in the STATUS register.


Sending Data

  1. Make sure CE is LOW
  2. Write the receivers pipe address in the TX_ADDR register (receivers pipe address and address width must match transmitter settings above)
  3. Copy the same address from TX_ADDR to Pipe 0 on  RX_ADDR_P0 register  because after transmit the NRF momentarily becomes a receiver to listen for the auto ACK and it listens on Pipe 0. Remember the address you are transmitting is at least 3 bytes long depending on the width setting. You must write that same amount of bytes in the TX_ADDR register and Pipe 0 address register 
  4. Send the TX_PAYLOAD command
  5. Send the payload data.
  6. Drive the CE pin HIGH for a minimum of 10us to start the transmission and then bring it back LOW
  7. Next just handle the TX_DS interrupt or MAX_RT interrupts as you wish. Hopefully you dont get the MAX_RT interrupt because that means the data did not send, meaning there was no auto ACK received. Also if you send payloads too fast you will get a few MAX_RT interrupts because the module is not that fast and it takes time to transmit as well as get a reply.


Receiving 


Setup

  1. The CE pin must start out LOW, because a HIGH to LOW transition is what causes the transmission to start. So before anything is done make sure the CE pin is LOW alos the CE pin should not be held high for too long. but the NRF takes care of that in Enhanced Shockburst mode.
  2. Next you want to power up the chip internally by setting the PWR_UP bit in the CONFIG register
  3. Set (1) the PRIM_RX bit in the CONFIG register to use the NRF as a receiver
  4. Set CRC encoding scheme 1 byte or 2 bytes , by setting or clearing the CRCO bit in the CONFIG register
  5. Enable the CRC itself by setting the EN_CRC bit in the CONFIG register, you can skip this since enabling auto ACK on any pipe will force this bit high anyways.
  6. Set the interrupts desired in the CONFIG register, clearing them (0) means they will be active.
  7. Enable the pipe you are using in the EN_RX_ADDR register
  8. Enable auto ACK on the pipe you are using in the EN_AA register
  9. Set the data width you are expecting in RX_PW_P#
  10. Set address width in the SETUP_AW register
  11. Set the address you want the pipe to have, in the RX_ADDR_P# register
  12. This part requires a diagram. Because if you are using a pipe with only 1 address byte, but address width is only allowed to be 3 or or 5 then how can the pipe address only be 1 byte? 
    


Using the image above as an example this is how the receiver address works.

Lets say you want to use Pipe 5 and a address width of 3 bytes. So you set a custom address in Pipe 5 of 0xAA. 
However that only counts as 1 byte, the least significant byte. Since you want 3 bytes of address width then byte 2 comes from byte 2 of Pipe 1 address. And byte 3 comes from byte 3 of Pipe 1 address. If you wanted 5 bytes address width the pattern continues.  So your final real address is 0xDDCCAA and this is what must be put into the transmitter TX_ADDR and transmitter PIPE 0 (not in the receiver device just the transmitter device)
This can get confusing sometimes but the driver we write will handle it, or  you can just use default values for all the addresses and it works fine.
One more example : if you want the address to truely be 0xAA then you puit oxAA in Pipe 5 and fille Pipe 1 with all 0x0000000000 still your address width is 3 bytes but leading 2 bytes are 0. 
Then in the transmitter device you would write 0x00000000AA in TX_ADDR and Pipe 0

Try to remember the address in the receiver is connected to Pipe 1 (RX and Pipe 1)
The address the transmitter transmits to must be the same in TX_ADDR and Pipe 0  ( TX and Pipe 0)

Receiving Data

Listening for data and retrieving it is quite easy

  1. To start listening for packets in the air simply make the CE pin HIGH
  2. When a packet comes in the RX_DR interrupt will trigger in the STATUS register
  3. The RX_P_NO in the STATUS register will tell you what Pipe the data arrived in, if you only activated one pipe then you should know, but if you have more than one pipe active these bits will tell you.
  4. At this point you can bring the CE pin back LOW to stop listening.
  5. Send the R_RX_PAYLOAD command to retrieve the data.
  6. Clear the interrupt by writing a 1 to it in the STATUS register
  7. Now you can do as you please, put CE HIGH again to listen for more packets or whatever you want to do next.


All of this will make much better sense when we get into the code and may not even sound so complex once  you see how easy the code looks. See you in the next post.



<< PREVIOUS | NEXT >>













Comments

Share your comments with me

Archive

Contact Form

Send