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.
- 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.
- 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.
- 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:
- 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.
- Next you want to power up the chip internally by setting the PWR_UP bit in the CONFIG register
- Clear (0) the PRIM_RX bit in the CONFIG register to use the NRF as a transmitter
- Set CRC encoding scheme 1 byte or 2 bytes , by setting or clearing the CRCO bit in the CONFIG register
- 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.
- Set the interrupts desired in the CONFIG register, clearing them (0) means they will be active.
- Set address width in the SETUP_AW
- Setup wait time in between re-transmissions after a failed transmission
- Setup max number of re-transmits
- As a safety measure clear interrupt flags in the STATUS register.
Sending Data
- Make sure CE is LOW
- Write the receivers pipe address in the TX_ADDR register (receivers pipe address and address width must match transmitter settings above)
- 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
- Send the TX_PAYLOAD command
- Send the payload data.
- Drive the CE pin HIGH for a minimum of 10us to start the transmission and then bring it back LOW
- 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
- 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.
- Next you want to power up the chip internally by setting the PWR_UP bit in the CONFIG register
- Set (1) the PRIM_RX bit in the CONFIG register to use the NRF as a receiver
- Set CRC encoding scheme 1 byte or 2 bytes , by setting or clearing the CRCO bit in the CONFIG register
- 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.
- Set the interrupts desired in the CONFIG register, clearing them (0) means they will be active.
- Enable the pipe you are using in the EN_RX_ADDR register
- Enable auto ACK on the pipe you are using in the EN_AA register
- Set the data width you are expecting in RX_PW_P#
- Set address width in the SETUP_AW register
- Set the address you want the pipe to have, in the RX_ADDR_P# register
- 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
- To start listening for packets in the air simply make the CE pin HIGH
- When a packet comes in the RX_DR interrupt will trigger in the STATUS register
- 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.
- At this point you can bring the CE pin back LOW to stop listening.
- Send the R_RX_PAYLOAD command to retrieve the data.
- Clear the interrupt by writing a 1 to it in the STATUS register
- 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.
Comments