Warning: This is old documentation, and should only be used for historic reference. Please go here to find the latest.
nRF51 SDK
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
Enhanced ShockBurst User Guide

User Guide for Enhanced ShockBurst library. More...

Introduction

Enhanced ShockBurst (ESB) is a basic protocol supporting two-way data packet communication including packet buffering, packet acknowledgement and automatic retransmission of lost packets.

The ESB protocol was embedded in hardware in the legacy nRF24Lxx series from Nordic Semiconductor. The nRF51 ESB software library enables an nRF51 device to communicate with a nRF24Lxx device using the ESB protocol.

ESB features automatic packet transaction handling for easy implementation of a reliable bi-directional data link. A transaction is a packet exchange between two transceivers, with one transceiver acting as the Primary Receiver (PRX) and the other transceiver acting as the Primary Transmitter (PTX).

esb_fig1_star_network.png
Enhanced ShockBurst network

Features

Packet transaction

An Enhanced ShockBurst packet transaction is initiated by a packet transmission from the PTX and successfully completed when the PTX has received an acknowledgment packet (ACK packet) in return from the PRX.

To enable a bi-directional data link the PRX is allowed to attach a data payload to the ACK packet. This can be done by uploading packet(s) to the TX FIFO(s) on the PRX.

esb_fig2_ptx_trans_ok.png
PTX to PRX packet transaction

If the PTX does not receive the ACK after the initial transmitted packet, it will attempt to retransmit the packet until the ACK is finally being received. The maximum number of allowed retransmission attempts are specified by the nrf_esb_set_max_number_of_tx_attempts() function, and the delay in between each transmission attempt is specified using the nrf_esb_set_retransmit_delay() function.

The retransmission delay is defined as the duration between the start of each transmission attempt. Note that this differs from the legacy nRF24Lxx hardware implementation, where this delay was defined as the duration from the end of a packet transmission until the start of the retransmission.

In the case where only the ACK packet sent from the PRX to the PTX is lost, but both the initial packet and the subsequent retransmission attempts are being successfully received by the PRX, the repeated packets will be discarded by the PRX, but the ACK packets will still be sent in return to the PTX. This prevents the application receiving duplicate data packets at the PRX.

esb_fig3_prx_ptx_trans_fail.png
Failed package transaction.

A PTX can select that individual packets transmitted to the PRX shall not require an ACK to be sent in return from the PRX. This decision is taken by the application when uploading a packet to the TX FIFO using the packet_type parameter of the nrf_esb_add_packet_to_tx_fifo() function.

When the PRX receives a packet not requiring an ACK it will not send an ACK packet in return to the PTX, and as a result the PTX will continue retransmitting the packet until the maximum number of allowed retransmission attempts is reached.

Getting started

The typical ESB application has the following steps:

ESB can also be disabled at any time using the nrf_esb_disable() function. When this is called ESB will complete any ongoing transaction before being disabled. When any ongoing transaction is completed and ESB has been disabled, the nrf_esb_disabled() callback will be called.

Frequency selection

ESB can send or receive packets using one of 126 frequency channels as selected by the function nrf_esb_set_channel().

In order to exchange packets between a PTX and a PRX these must be configured using the same frequency channel.

Pipes and addressing

Each PTX or PRX node uses the term "pipe" as a logical address for communication with another node. Each pipe maps to one actual physical on-air address used when transmitting or receiving packets.

The actual on-air physical addresses are composed of a 2-4 byte long "base address" in addition to a 1 byte prefix address. Note that the nRF51 radio uses an alternating sequence of 0s and 1s as the preamble of the packet. Therefore for packets to be received correctly, the most significant byte of the base address should not be an alternating sequence of 0s and 1s i.e. it should not be 0x55 or 0xAA.

Pipe 0 has its own unique base address, which is base address 0, while pipes 1-7 use the same base address, which is base address 1.

Each of the 8 pipes have a unique byte-long prefix address.

On air, the most significant bit of each address byte will be transmitted first. The most significant byte of the 4 byte long base address is the first transmitted address byte, while the prefix byte is transmitted last.

Packet identification

Any packet transmitted from a PTX to a PRX is uniquely identified by a two bit packet ID field (PID) in the packet header together with the packet's Cyclic Redundancy Check (CRC) field. This packet ID is used to distinguish a new packet from the previous packet if it has the same payload.

At the PRX, retransmitted packets will be discarded and not added to an RX FIFO. The nrf_esb_rx_data_ready() will not be called.

The CRC is used in addition to the PID to identify a unique packet. This reduces the likelihood of a packet being falsely identified as a retransmission attempt and discarded by the PRX when several consecutive failed packet transmission attempts occur. This feature is helpful as the PID is only two bits.

FIFO handling

All eight pipes on both the PTX and the PRX have two multi level FIFOs that can hold packets, that is each pipe's TX FIFO and RX FIFO.

PTX FIFO handling

When ESB is enabled in PTX mode, any packets uploaded to a TX FIFO will be transmitted at the next opportunity. If several TX FIFOs contain packets, the various TX FIFOs will be serviced in a round robin fashion, meaning that no TX FIFO will experience starvation even when packets are continuously being added to other TX FIFOs.

When an ACK is successfully received from a PRX, it implies that the payload was successfully received and added to the PRX's RX FIFO, the successfully transmitted packet will be removed from the TX FIFO so that the next packet in the FIFO can be transmitted.

If an ACK received by a PTX contains a payload, this payload will be added to the pipe's RX FIFO.

If the RX FIFO for a specific pipe on a PTX is full and can not accommodate any new packets, no new packets will be sent from the PTX on this pipe. In this case, we will never end up in the situation where a payload received in an ACK will have to be discarded due to the pipe's RX FIFO being full.

In addition, ESB limits the total number of packets in the FIFOs, which is smaller than the total size of all the FIFOs. Therefore, a PTX will also refuse to add a packet to the TX FIFO if it doesn't have space for the packet as well as the corresponding ACK.

PRX FIFO handling

When ESB is enabled in PRX mode, all enabled pipes (addresses) are simultaneously monitored for incoming packets.

If a new packet not previously added to the pipe's RX FIFO is received, and the pipe's RX FIFO has available space for the packet, the packet will be added to the RX FIFO and an ACK will be sent in return to the PTX. If the pipe's TX FIFO contains any packets, the next serviceable packet in the TX FIFO will be attached as a payload in the ACK packet. In order for a TX packet to be attached to an ACK, this TX packet would have to be uploaded to the TX FIFO before the packet is received.

As we can not ensure that the ACK always will be successfully received by the PTX, the data payload added to the ACK will not be removed from the TX FIFO immediately. This TX packet will be removed from the TX FIFO when a new packet (new packet ID or CRC) is received on the same pipe. In this case, the new packet sent as an ACK will serve as a kind of acknowledgement from the PTX saying that the previous ACK from the PRX was successfully received by the PTX. ACKs sent in reply to retransmission attempts will all contain the same TX payload.

Callback queuing

ESB contains an internal callback queue for queuing pending callbacks. This allows the application to queue callback functions while the application is already servicing a previously called callback function. In addition this allows the ESB process to function uninterrupted.

As an example, if a new packet is being received while the application is already servicing the nrf_esb_rx_data_ready() callback from a previously received packet, the nrf_esb_rx_data_ready() callback for the latest packet will be added to the callback queue and serviced at a later opportunity. In this case, nrf_esb_rx_data_ready() will be called one time for every received packet, and the application does not need to handle the potential race condition scenario where a new packet is being received just before the application is about to exit the nrf_esb_rx_data_ready() function.

Similarly, ESB will call the nrf_esb_tx_success() once for every transmitted packet, even when a new packet is being transmitted while the application is servicing the nrf_esb_tx_success() callback of a previously transmitted packet.

The callback queue can hold up to 10 pending callback functions.

Resources

ESB makes use of the following resources and requires exclusive access to them in order for ESB to ensure correct operation:

The radio and timer interrupt handlers run at priority level 0 (highest level), and the ESB callback functions run at priority level 1. Applications should run at priority level 2 or higher in order to ensure correct operation.

Backwards Compatibility

ESB for nRF51 supports the following minimum timeslot periods.

The nRF24Lxx ESB examples found in the legacy nRFgo SDK do not work out of the box with the nRF51 ESB examples. The retransmit delay and channel tables require adjustment.

The legacy examples need to add the following in order to work with the nRF51 examples. In addition, the legacy PTX example must add code for handling the payloads received in ACK.

hal_nrf_setup_dynamic_payload(0xFF);
hal_nrf_enable_dynamic_payload(true);
hal_nrf_enable_ack_payload(true);
hal_nrf_set_rf_channel(10);