Gazell Link Layer
Gazell is a protocol for setting up a robust wireless link between a single Host and up to eight Devices in a star network topology.
It is designed to minimize power consumption in power-sensitive wireless desktop products and is also suitable for a range of other wireless applications.
To minimize the power consumption of the power-sensitive peripheral devices, Gazell uses the central hub (host side) with its more relaxed power constraints to keep the link open while the peripheral devices can sleep and save on power consumption.
A typical example of this is a wireless mouse communicating with a USB dongle that is inserted into a computer.
Gazell provides a switching and synchronization scheme that reduces interference and provides wireless coexistence features, enabling high throughput and low latency.
Gazell provides the following features:
Support for star network topology with one Host and up to eight Devices.
Bidirectional data transfer between each Host and Device.
Channel hopping functionality that gives a reliable wireless link in environments with interference from other radio sources.
Packet acknowledgment and automatic packet retransmission functionality to prevent data loss.
Individual TX and RX FIFOs for every data pipe.
Backward compatible with legacy nRF24L Series Gazell.
Devices self-synchronize to the Host, meaning:
No connection packets are required to setup a link.
No polling packets are required to maintain a link.
Devices can enter and remove themselves from the network at any time.
Capability to control the RF front-end module.
Generates transmission statistics for each RF channel.
To enable the Gazell support in the nRF Connect SDK, set the following Kconfig options:
Gazell uses a fixed set of peripheral resources in the nRF5 SoC.
To ensure correct operation, Gazell requires exclusive access to the following resources:
Three PPI channels
Software interrupt (SWI)
The Gazell Link Layer glue module specifies the resources used by the Gazell Link Layer library.
The Gazell interrupt priorities are configured by applications.
The radio and timer interrupt handlers should run at priority level 0 (highest priority), and the Gazell callback functions can run at priority level 1.
To avoid blocking Gazell operations, applications can run at priority level 2 or higher.
You can customize Gazell at runtime for a range of different applications.
See the API documentation for a list of configuration functions as well as the default and constant parameters.
A member of a Gazell star network is either a Host or Device.
Up to eight Devices can communicate with a single Host.
Each Host can communicate with up to eight Devices.
Each Device communicates to a single Host.
Gazell star network
Once enabled, the Host in a Gazell network is always listening, and the Device always initiates the communication.
Each packet that a Device sends is required to be acknowledged by the Host.
The Host can send data to the Device by piggybacking data in an acknowledgment (ACK) packet.
Therefore, the Host must wait for a packet from the Device before it can send any data to it.
You can build more sophisticated Gazell networks, since a single Device can speak to several Hosts and any node can change between the two modes.
However, this requires the application to coordinate such a network.
This document focuses on the typical use case of a star network with static modes.
Gazell automatically takes care of all synchronization and packet handling.
You need to add payloads to the transmit (TX) FIFOs and read payloads from the receive (RX) FIFOs.
Gazell automatically notifies the application when a packet is received.
To set up a Gazell application, do the following:
Initialize GZLL glue code using
Initialize Gazell using
nrf_gzll_init() and choose either Host or Device.
Reconfigure Gazell’s default parameters.
At a minimum, reconfigure the addresses and channels to avoid interfering with other Gazell networks.
Enable Gazell using
If the node is a Device, start sending:
If the node is a Host, start listening:
You can also disable Gazell at any time using the
When this is called, Gazell completes any ongoing transmission or reception before being disabled.
(That is, until the end of the current timeslot, see Timeslots).
When the disabling operation is complete, Gazell calls the
When this callback is completed, the Gazell CPU context, radio and Gazell timer stop.
You can now call any of the configuration set functions, which will be valid, once Gazell is enabled again.
A typical packet transaction between a Device and a Host consists of a Device initiating the transaction by sending a data packet to the Host and the Host sending an ACK packet in return.
When the Device receives an ACK packet, it knows that the initial packet was successfully transmitted and the
nrf_gzll_device_tx_success() callback function is called to notify the application of this.
Similarly, when the Host receives the initial packet, the
nrf_gzll_host_rx_data_ready() callback function is called to notify to the application that a new packet has been received.
Successful packet transaction
A transaction can fail if the Host did not receive the initial packet from the Device, or the Device did not receive the corresponding ACK packet correctly.
Gazell ignores packets with a failing Cyclic Redundancy Check (CRC).
If a transaction fails, the Device makes an attempt to retransmit the initial packet to the Host until the ACK is finally received or the maximum number of transmission attempts is reached.
If the maximum number of transmission attempts is reached, the retransmissions stop and the
nrf_gzll_device_tx_failed() callback is called.
If only the ACK packet sent from the Host to the Device is lost, but the Host receives successfully both the initial packet and the subsequent retransmission attempts, the Host discards the repeated packets.
The ACK packets are still sent in return to the Device.
This prevents the application receiving duplicate data packets at the Host.
Example on failing packet transaction.
In the figure, the maximum number of allowed transmission attempts is set to 3.
Any packet transmitted from a Device to a Host is uniquely identified by a two bit packet ID field in the packet header together with the packet’s 16-bit Cyclic Redundancy Check (CRC).
This packet ID is used to distinguish a new packet from the previous packet, if it has the same payload.
On the Host side, retransmitted packets are discarded and not added to an RX FIFO.
Each logical address on the nodes is termed a pipe.
Each pipe maps to one on-air address used when transmitting or receiving packets.
The on-air addresses are composed of a 2-4 bytes long “base address” in addition to a 1-byte prefix address.
The nRF5 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, that is, 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 eight pipes have a unique byte-long prefix address.
On-air, the most significant bit of each address byte is transmitted first.
The most significant byte of the four bytes long base address is the first transmitted address byte, while the prefix byte is transmitted last.
All eight pipes on both the Device and the Host have two first in first out (FIFO) buffers that can hold packets.
Each pipe has a TX FIFO and an RX FIFO.
The total number of packets in the FIFOs is six, while every individual TX or RX FIFO (8 pipes x 2 = 16 in total) can store three packets.
When Gazell is enabled in Device 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 are serviced in a round robin fashion, meaning that no TX FIFOs will experience starvation even when packets are continuously added to other TX FIFOs.
When an ACK is successfully received from a Host, it implies that the payload was successfully received and added to the Host’s RX FIFO.
The successfully transmitted packet is removed from the TX FIFO so that the next packet in the FIFO can be transmitted.
If an ACK received by a Device contains a payload, it is added to the pipe’s RX FIFO.
If the RX FIFO for a specific pipe on a Device is full and cannot accommodate any new packets, no new packets are sent from the Device on this pipe.
A payload received in an ACK does not need to be discarded due to a full RX FIFO.
When Gazell is enabled in Host mode, all enabled pipes (addresses) are simultaneously monitored for incoming packets.
If a new packet is received and the pipe’s RX FIFO has available space, it is added to the RX FIFO and an ACK is sent in return to the Device.
If the pipe’s TX FIFO contains any packets, the next serviceable packet is attached as a payload in the ACK packet.
To have a TX packet attached to an ACK, it needs to be uploaded to the TX FIFO before the packet is received.
Since the Device does not always receive the ACK successfully, the data payload added to the ACK is not removed from the TX FIFO immediately.
The TX packet is removed from the TX FIFO when a new packet (new packet ID or CRC) is received on the same pipe.
The new packet sent from the Device serves as an acknowledgment of the ACK sent previously by the Host.
ACKs sent in reply to retransmission attempts contain the same TX payload.
When the Host is handling packets on multiple pipes, ensure the ACK payloads in the TX FIFOs on pipes that are no longer used, are not taking up space in the memory pool and consequently blocking communication on other pipes.
To avoid such congestion, the application on the Host can flush the TX FIFOs on the unused pipes.
Gazell has an internal callback queue for queueing pending callbacks.
This queue steps in when Gazell attempts to call a new callback function while the application is already servicing the previous one.
For example, if a new packet is received by the Host while the application is already servicing the
nrf_gzll_host_rx_data_ready() callback from a previously received packet, the callback for the latest packet is added to the callback queue and serviced at a later opportunity.
In this case,
nrf_gzll_host_rx_data_ready() is called once 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
In a Device, the
nrf_gzll_device_tx_success() callback is called once for every packet receiving an ACK, even when a new packet is receiving an ACK while the application is servicing the callback of a previously transmitted packet.
The size of the callback queue is given by
NRF_GZLL_CONST_CALLBACK_QUEUE_LENGTH but it cannot be configured.
Timeslot is a core parameter in Gazell.
It can be seen as the internal Gazell “heartbeat”.
In a Device, any packet transmission (both new packets and retransmitted packets) starts at the beginning of a timeslot, and only one packet transmission (including ACK) can take place within a timeslot.
Relation between Device operation and timeslot
On the Host side, the radio initiates a radio startup at the beginning of the timeslot to start listening.
In addition, it may optionally change the RF channel it listens to.
Relation between Host operation and timeslot
To set the period for the heartbeat, use the
To ensure good coexistence performance with other radio products operating in the same 2.4 GHz frequency band as Gazell, such as Wi-Fi or Bluetooth, Gazell implements mechanisms for hopping between various radio frequency channels.
When enabled, Gazell picks channels from a predefined channel table.
The application can reconfigure the contents and size of the channel table.
The Device and Host must be configured to have the exact same channel table.
The application can pick from a full set of 80 channels.
A table of 3-7 channels is proven to give a satisfactory coexistence performance in most environments.
Too large channel table may increase the transmission latency and power consumption, while using a too small channel table may decrease the coexistence performance.
The core parameters deciding the channel hopping behavior are:
Which one to use depends on whether Gazell is “in sync” or “out of sync”, see Synchronization.
timeslots_per_channel is used instead of these terms.
timeslots_per_channel parameter sets the number of timeslots Gazell has on a single channel before the channel is changed.
In the next timeslot with a channel shift, Gazell picks the next channel from the predefined channel table, cycling back to the beginning of the channel table if required.
Host and Device channel switching. Here, timeslots_per_channel = 2.
In Device mode,
timeslots_per_channel can also be seen as the number of transmission attempts spent on each channel before switching the channel.
This is because there is at least one transmission attempt for every timeslot.
channel_selection_policy parameter is used by a Device in sync to decide the initial channel to be used when sending a new packet to a Host (that is, for the first time the new packet is sent, not for the retransmission attempts).
Once synchronized with the Host, the Device can send either on the current channel that it believes the Host is on or on the last successful channel.
To configure this, use the
channel_selection_policy parameter can take the following two values:
If you choose the
NRF_GZLL_DEVICE_CHANNEL_SELECTION_POLICY_USE_SUCCESSFUL policy, the Device starts sending packets on the channel it last had a successfully acknowledged transmission.
This policy is the most robust against static interference.
Once the Device finds a quiet channel, it should be able to continue using this channel.
If you choose the
NRF_GZLL_DEVICE_CHANNEL_SELECTION_POLICY_USE_CURRENT policy, the Device sends on the channel it believes the Host is currently listening to.
This achieves the lowest latency and highest throughput of the two policies as the Device does not have to wait for the Host to be listening to a specific channel.
This policy is frequency hopping.
The disadvantage of this policy is that if there is static interference on a particular channel, the Device wastes packets attempting to send on this channel.
The application can reconfigure the channel table during runtime to overcome this.
The channel selection policy only applies to the initially transmitted packet.
If the transmission of this initial packet fails, the following retransmission attempts are always sent in the channel the Device believes the Host is monitoring.
If Gazell is “out of sync”, it always starts the packet transmission immediately using the previous successful transmission channel.
If Gazell has not transmitted a successful packet and thus has no previous successful channel to relate to, it starts using the first channel in the channel table.
The internal timeslot, or “heartbeat”, mechanism of Gazell is used to obtain synchronous communication while still enabling efficient channel switching.
This mechanism is useful when a Device needs to switch to a new channel while there is radio interference on the current channel.
Each Gazell Device has two synchronization states: in sync and out of sync.
On the Host, the internal heartbeat timer is always running when Gazell is enabled, independent of the Devices’ synchronization state.
On the Device, the heartbeat timer only runs as long as the Device is “in sync” or as long as there are packets to be sent.
If the timer has been stopped and packets are added to a TX FIFO, the timer starts immediately.
Before any packets have been successfully received and acknowledged, the Device is out of sync.
In this state, the Device switches channel determined by the
The Device switches channel at a slower rate than the Host (as determined by
timeslots_per_channel) so that the Device eventually transmits a packet on the same channel that the Host is on.
When a Device successfully transmits a packet, that is when an ACK packet is received from the Host, it enters the in sync state, as it now has the information needed for continuing to guess the following channels the Host is listening to.
For knowing when to change channel, Gazell has an internal
timeslot_counter to count the number of timeslots it has on a single channel.
When this counter reaches
timeslot_counter is reset and the
channel_index is incremented (cyclically).
When the Device has received an ACK, it knows the Host is using the current channel, but it does not know the
timeslot_counter state on the Host.
As a result, only in the timeslots where the
timeslot_counter equals zero the Device can be confident that it “guesses” the correct channel that the Host is monitoring.
Therefore, when an ACK is received, the
timeslot_counter for the current timeslot is reset to zero, and a new Device transmission starts when the
timeslot_index counter on the Device is zero.
Retransmission attempts, however, are sent on all timeslots.
Once the Device is in sync, it keeps an internal timer running to maintain the internal heartbeat in order to remain synchronized with the Host.
The duration the Device stays in the in sync state is the
sync_lifetime and is measured in timeslots.
sync_lifetime is reset whenever a packet is received.
sync_lifetime has expired on a Device, the internal timer is stopped and the Device returns to out of sync state.
If you set the
sync_lifetime to zero, the Device will never be in sync.
sync_lifetime should be chosen with regard to how often packets are required to be sent and the fact that synchronization can only be maintained for a finite time due to clock drift and radio interference.
To configure the sync lifetime, use the
The Device knows it is in sync when the number of retransmissions gets close to zero.
nrf_gzll_device_tx_info_t structure is passed to the Device callback functions, and it contains the number of transmit attempts required for the current packet.
In addition, the structure contains the
num_channel_switches parameter that the application can use to determine whether the RF channels are reliable.
This enables the application to track bad channels and update the channel tables on Host and Device if desired.
The Gazell Link Layer examples are not fully “out of the box” compatible with the legacy examples provided in the nRFgo SDK for nRF24Lxx devices.
The default timeslot period and channel tables require adjustment, as well as some setup to emulate the Gazell modes.
The Gazell Low Power Host mode (Host mode 1) is not supported in the nRF5.
The default channel tables require adjustment.
Depending on your project, do one of the following:
The Gazell Link Layer supports the following minimum timeslot periods:
600 us timeslot period, nRF5 Gazell Device to nRF5 Gazell Host.
504 us timeslot period, nRF5 Gazell Device to nRF24Lxx Gazell Host.
When using 504 us timeslot period, the following restrictions apply:
In addition, the relation between the Device and Host timing parameters should be as follows:
The Host listens to each channel in a GZLL_RX_PERIOD number of microseconds, where GZLL_RX_PERIOD is the heartbeat interval in the nRF24Lxx devices.
The Host GZLL_RX_PERIOD must be greater than the time required to make two full transmission attempts on the Device (including ACK wait time).
Depending on your project, do one of the following:
The Gazell Link Layer protocol for the nRF5 Series is compatible with the most useful modes of the Gazell Link Layer for the nRF24Lxx devices.
Emulating legacy nRF24Lxx Gazell Device mode 2 and nRF24Lxx Host mode 0
You can emulate the legacy Device mode 2 as follows:
The channel selection policy is equivalent to
When Gazell is out of sync, a large number of attempts may occur on each channel before the channel is switched.
When Gazell is in sync, a low number of transmission attempts, typically two, are allowed on each channel before the channel is switched.
The legacy Host mode 0 behaves as follows:
Host is always on while it is enabled.
When enabled, the Host will continuously cycle through the channel table.
See the example on how to achieve such behavior.
Assuming a channel table
my_channel_table with three channels:
/* On Host and Device */
timeslots_per_channel = 2;
channel_table_size = 3;
nrf_gzll_set_timeslot_period(GZLL_RX_PERIOD / 2);
/* On the Device */
Emulating legacy Gazell
The Gazell stack allows to automatically gather transmission information, such as:
Total number of transmitted packets.
Total number of transmission timeouts.
Number of transmitted packets on each RF channel.
Number of transmission failures on each RF channel.
The stack can also track packet transaction failure events, such as transmission timeout or receiving a packet with incorrect CRC.
To turn on transmission statistics, perform the following steps:
This is a buffer for transmission statistics data, so it must remain in memory as long as the transmission statistics are used.
nrf_gzll_init() to initialize Gazell.
nrf_gzll_tx_statistics_enable() function to enable transmission information gathering.
After this, transmission statistics can be read from the defined structure.
To reset the recording, call the
To track packet transaction failures, perform the following steps:
nrf_gzll_crc_failure_callback functions that will be called on a proper event.
nrf_gzll_init() to initialize Gazell.
Register the defined callbacks by calling
After this, each transmission timeout and received packet CRC failure will be reported by the respective callback.