Bluetooth works in the 2.4GHz frequency range. Since this is an ISM band, there is a high possibility for interference with other devices working in the same frequency band. The Bluetooth standard makes it possible for the communicating devices to agree on which channels to use from the 37 available data channels during communication. If the master device detects high interference on a channel it can initiate a channel map update. Adaptive frequency hopping (AFH) means, that the communicating devices are continuously monitoring their environment for interference, and they are continuously changing the channel map according to the interference.
Note: AFH is a requirement if you want to use Tx power over +10dBm, see Bluetooth Tx power settings.
Channel map update procedure is part of the Bluetooth 4.0 specification. This procedure makes it possible for the peer devices to agree on which channels they will use from the available 37 data channels during communication. Channel map update procedure can be initiated by the master only.
Being part of the Bluetooth 4.0 standard, this procedure is supported in all SDK versions. E.g. if a smartphone connects to an EFR device, then the smartphone - being a master - can disable some channels, and the EFR will accept it. This feature is very often used to disable the Bluetooth channels that overlap with the WiFi channel used by the smartphone!
However, in the case when the EFR is the master, the EFR will enable all channels by default, without any restriction, and they can be disabled only manually - see section Manual Channel Blocking. Adaptive Frequency Hopping was introduced to overcome this issue, and to block low-quality channels dynamically.
Since Bluetooth SDK v2.9 adaptive frequency hopping can be enabled by calling
gecko_init(&config);. (Note, that AFH implementation was in beta phase in Bluetooth SDK v2.9, and you should use Bluetooth SDK v2.10 or later for certifiable implementation.)
If AFH is enabled (and at least one advertiser is running with extended advertisements or at least one connection is active), the Bluetooth stack runs a periodic background task that sweeps all channels once every
afh_scan_interval and measures received power on each channel. If the measured power is beyond a limit (-71dBm) on a channel, then the channel is blocked for at least 8
afh_scan_intervals. (If interference is still found on the channel, the blocking is prolonged, i.e. unblocking of a channel needs 8 consecutive measurements with no interference detected.)
After each sweep a new channel map is created based on the interference measurements. If the channel map has changed, then the master device sends the new channel map to all slaves, using the channel map update process. Slaves cannot initiate channel map update.
ah_scan_interval is set to 1 second by default and the sweep of the 40 channels takes around 10ms. This means an additive energy consumption of ca. 240uW.
Note: The AFH sweep has the highest priority among all Bluetooth operations, which means, if there are multiple operations within 10ms, then sweeping cannot be fitted between them and they may be blocked.
afh_scan_interval is set to 1 second by default., i.e. one channel sweep is made every second. Before Bluetooth SDK v2.11 this value was fixed. From Bluetooth SDK v2.11 this value can be changed at any time by calling the following function:
#define AFH_SCAN_INTERVAL_CONFIG_KEY 7 uint8_t afh_scan_interval = 10; // set afh scan interval to 100ms gecko_cmd_system_linklayer_configure(AFH_SCAN_INTERVAL_CONFIG_KEY,sizeof(uint8_t),&afh_scan_interval);
The unit of
afh_scan_interval is 10ms.
Channel sweep is always done after a radio operation, e.g. after an advertisement was sent. Setting the scan interval e.g. to 100ms does not mean that the sweep will be done every 100ms, but that after every radio operation the Bluetooth stack checks if at least 100ms has passed since the last sweep. Let's say that
afh_scan_interval is set to 100ms and we are advertising with 80ms advertisement interval. In this case the scan is done after every second advertisement, i.e. once every 160ms.
Channels can be blocked manually as well using the following command:
gecko_cmd_le_gap_set_data_channel_classification(). For details see the Bluetooth API Reference Manual. If a channel is blocked manually that channel will be never used - until it is unblocked manually. With other words, the channels blocked by interference detection and channels blocked manually will be merged into a common channel map.
You are allowed to use Tx power above +10dBm when AFH is enabled and at least 15 channels are available, see Bluetooth Tx power settings. However, you have to be aware, that high transmit power is only allowed once for each channel after a measurement on that channel happened. This means that if you use the same channel multiple times for transmitting within
afh_scan_interval, then the second and consecutive transmission will use +10dBm. If you have a short connection interval and long afh_scan_interval, this can easily happen, see the following figure:
To be ETSI compliant slave devices need to be adaptive as well. The master might be non-adaptive, so the slave cannot blindly follow the transmissions of the master. ETSI allows using control transfer on blocked channels with +10dBm or lower, but not data transfer. For ETSI compliance reasons, if the slave detects that a blocked channel is used it will only send a single empty/control packet on that channel to prevent supervision timeout.
Bluetooth Low Energy has two kind of channel selection algorithms. Algorithm #1 is the original and mandatory to support. Algorithm #2 was introduced with Bluetooth 5.0. The hopping algorithm used is chosen by the master at connection time. Algorithm #2 has more randomness so it is used always unless connecting to a legacy device.
If a channel to be used is blocked on the channel map, then the channel is remapped to an available channel using a remapping algorithm.
When AFH is applied, the length of the connection events (not to be confused with the connection interval!) are limited to 40ms. This means that in every connection interval you can send packets only for 40ms long. This is usually not a problem, as it takes around 2.5ms to transmit a packet with 251B payload. But if you want to achieve maximum throughput with unacknowledged data transmission (see Throughput with Bluetooth Low Energy) then you have to take into account this limitation. E.g. if you have 100ms connection interval, then you can send packets only in 40% of the time. To achieve maximum throughput, decrease your connection interval to 40ms or lower.