Showing posts with label pipe. Show all posts
Showing posts with label pipe. Show all posts

Thursday, April 4, 2013

RF24 - Avoiding RX Pipe 0 For Enhanced Reliability

RX Pipe 0 Is Special


The NRF24L01(+) radios have six receiving hardware pipes as part of its MultiCeiver design. These pipes, zero through five [0-5], each can have their own address. This sounds great, but reality is, pipe 0 is special.

Pipe 0 is special because, whenever you transmit, RX pipe 0 is changed to that of the writing pipe's address. The fact this occurs is obscured, by design, by the RF24 driver. This is because the RF24 driver has specific logic for pipe 0. This is primarily why the startListening() method exists. Every time a call to startListening() is made, the RX pipe 0 address is shuffled back into the radio. Its shuffled in because whenever the radio transmits, the RX pipe 0 address is internally replaced by the radio.

While not explicitly declared in the data sheet, I believe I understand why this behaviour takes place. When you enable auto-acknowledgement, the receiving radio needs to reliably inform the transmitter of its ACK/NAK status. In turn, potentially returning an ACK payload. However, the receiver doesn't directly know who transmitted the message. Its not part of the message. In order for the receiver to reply, the transmitter must be prepared to listen for a reply back from the receiving radio. As such, if the radio simply listens for a reply using the destination address, it should always match and filter properly. This is a clever idea to prevent transmitting source addresses.

That's fine and all, and is rather clever, but there is a problem. The RF24 driver, in its attempt to hide this detail, creates an opportunity for lost and/or missed packets. Its a classic race condition. This is a race condition because, should a transmitter send a message before the application's call to startListening() completes, the radio will completely ignore the message. Even if received, it will be silently filtered out and ignored. That means all messages destined for RX pipe 0's address will be silently ignored until the reloading of RX pipe's address completes. That completion only takes place with a call to startListening().

This race condition is potentially compounded by the fact applications are free to have any amount of logic between the end of a write() or startWrite() call and the completion of a startListening() call. For almost the entire duration between [write()/startWrite()] and startListening() calls, the radio will ignore all messages addressed to pipe 0's address.

The solution? Well, There really isn't a neat and clean solution. While many applications won't have issue with using RX pipe 0, and the associated message loss, high traffic networks are likely to suffer from periodic message loss and potential packet loss without full use of all retry attempts. For this second case, imagine the radio starts listening into 14-retries out of 15. That means all but one of the available retry opportunities have been lost simply because the radio was ignoring those messages. In turn, this would also drive up latency on the transmitter's side.

Long story short, if you want a reliable network, don't use RX pipe 0. For small networks, use is unlikely to cause significant issue. But for a better option, just pretend you only have RX pipes one through five (1-5); for a total of five, rather than six. But if you insist on using RX pipe 0, always ensure your [write()/startWrite()] calls are as close as is possible to your startListening() call, so as to minimize the window of potential lost packets.

Tuesday, April 2, 2013

Improve RF24 Radio Performance With Proper Addressing Schemes

RF24 Addressing Gotchas

The NRF24L01(+) radios require addresses be configured on each of its Multiciever pipelines. Without much thought, people assign addresses to these pipelines. This can be problematic because of RF decoding requirements as dictated by the preamble (data transmitted in front) of each message. Read 7.3.1 and 7.3.2 of the data sheet for more information.

A longer addressing scheme allows for more opportunity to disambiguate from the preamble. As such, in my opinion, the maximum available address length should be preferred. 40-bit addressing is most effective when proper addressing is provided to each pipeline. Per the data sheet, addresses which use single bit transitions should be avoided as they are more likely to confuse preamble message detection logic should the preamble become distorted from noise.

As such, addresses with the following octets and/or nibbles (half byte) should be avoided.

Octet values to avoid:
'0xaa' - '0b10101010'
'0x55' - '0b01010101'
'0x2a' - '0b00101010'
'0x15' - '0b00010101'

Nibble values to avoid:
'0x0a' - '0b00001010'
'0x05' - '0b00000101'
'0x02' - '0b00000010'
'0x01' - '0b00000001'

This in turn means addresses with those nibbles should not be used. Remember, a nibble is half an octet, so two of those nibbles can be used to create an octet. The octets of 0xaa and 0x55 are very bad. Always avoid them. Notice these appear in the octet list to avoid and that they are made up of a pair of nibbles from our nibble list to avoid. This is because both nibbles of both octets (both halves of the byte) are 0x0a or 0x05; making for an octet of 0xaa or 0x55. Accordingly, octets 0xaa and 0x55 represent the worst possible octet to use for an address because they exactly mirror the preamble of messages.

Other nibble combinations to avoid, for example, would be 0xa1, 0x52, x12, 0x25, so on and so on. But even simple octets, such as 0x01, 0x02, and 0x05, should also be avoided.

In general, use of values contained above is more likely to cause the loss of packets and in turn, require additional retransmissions if using the auto-acknowledgement hardware features.

But Wait, There's More

The list above is hardly the exclusive list of bit patterns to avoid. In section 7.3.2, the data sheet says, "Addresses where the level shifts only one time (that is, 000FFFFFFF) can often be detected in noise and can give a false detection, which may give a raised Packet Error Rate [(PER)]. Addresses as a continuation of the preamble (hi-low toggle; [single bit transitions, as referred above]) also raises the Packet Error Rate.

As such, an address of 0xFFFFFFFFFF should never be used. And in general, octet sequences of all bits on or off should be avoided. Which means, nibbles of 0x0F and 0x00 should be frowned upon.

Please note addressing is a little more complex and that the tips provided here. These tips should be regarded as rules of thumb rather than absolutes. Regardless, if you follow the advice here, your reliability is generally improved (PER is reduced).