Welcome to this tutorial on Bluetooth Development in C Programming. This is part of the free embedded systems course by EmbeddedPathashala. In this tutorial, we will explain what Adaptive Frequency Hopping (AFH) is, why we need it, how it works using LMP PDUs, and also cover Master/Slave roles and role switching in a Bluetooth piconet.
1. Frequency Hopping and the Interference Problem
Bluetooth Classic (BR/EDR) operates in the 2.4 GHz ISM band and uses Frequency Hopping Spread Spectrum (FHSS) to avoid sustained interference from other devices operating in the same band — such as Wi-Fi, microwave ovens, and other Bluetooth devices. The 2.4 GHz band is divided into 79 channels, each 1 MHz wide (channels 0–78). Bluetooth hops across these channels in a pseudo-random sequence at a rate of 1600 hops per second (one hop every 625 µs).
Although frequency hopping provides protection against sustained narrowband interference, it does not completely eliminate the problem. If a packet is transmitted on a channel that has interference at that moment, the data will be corrupted and must be retransmitted on the next available pseudo-random channel. Even if the retransmission succeeds, the original transmission was wasted, leading to a decrease in throughput as retransmissions increase.
Frequency (channels)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Ch 78 | . . . . . .
Ch 77 | . . . . .
Ch 76 | . . . . . .
... |
Ch 10 | [TX OK] [TX OK] [TX OK]
Ch 9 | [TX FAIL] [TX FAIL] [TX FAIL] <-- Wi-Fi noise
Ch 8 | [TX OK] [TX OK]
... |
Ch 2 | [TX OK] [TX OK] [TX OK] [TX OK]
Ch 1 | [TX FAIL] [TX FAIL] [TX FAIL] <-- Wi-Fi noise
Ch 0 | [TX OK] [TX OK] [TX OK] [TX OK]
+---------------------------------------------------------------->
Time (hops)
Result: Packets on noisy channels fail → retransmissions → throughput drops
2. What is Adaptive Frequency Hopping (AFH)?
Adaptive Frequency Hopping (AFH) was introduced in Bluetooth version 1.2. It solves the interference problem by dynamically identifying channels that have persistent interference and marking them as unused in a structure called the channel map. Frequency hopping then occurs only on the channels marked as used, completely avoiding the bad channels.
When AFH is enabled, the Master maintains the channel map and communicates it to all connected Slaves. The Slaves then exclude the unused channels from their frequency hopping pattern. This way, even though the total number of hopping channels is reduced, there are no wasted retransmissions on known bad channels, preserving throughput.
🗼 AFH Channel Map — Sample Snapshot (79 channels)
Used (good channel, included in hopping)
Unused (bad channel, excluded from hopping)
Channels 9, 10, 11, 21, 22, 23, 24, 25, 36, 37 shown as unused (simulating Wi-Fi overlap at typical channels).
Frequency (channels)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Ch 78 | [TX OK] [TX OK] [TX OK] [TX OK] [TX OK] [TX OK]
Ch 77 | [TX OK] [TX OK] [TX OK] [TX OK] [TX OK]
Ch 76 | [TX OK] [TX OK] [TX OK] [TX OK] [TX OK]
... |
Ch 10 | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX <-- Excluded by AFH (Wi-Fi)
Ch 9 | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX <-- Excluded by AFH (Wi-Fi)
... |
Ch 2 | [TX OK] [TX OK] [TX OK] [TX OK] [TX OK]
Ch 1 | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX <-- Excluded by AFH (Wi-Fi)
Ch 0 | [TX OK] [TX OK] [TX OK] [TX OK] [TX OK]
+---------------------------------------------------------------->
Time (hops)
Result: All transmissions land on clean channels → no retransmissions → throughput maintained
| Scenario | Behaviour | Throughput Impact |
|---|---|---|
| AFH Disabled | All 79 channels used for hopping. Packets on noisy channels fail and must be retransmitted. | 🔴 Decreases — retransmissions consume bandwidth |
| AFH Enabled | Only channels marked as used are included in the hop sequence. Noisy channels are avoided entirely. | 🟢 Maintained — fewer retransmissions, efficient use of clean channels |
3. AFH Channel Map
To use AFH, the Master maintains a data structure called the channel map. In this channel map, each of the 79 BR/EDR channels is classified as either:
- Used — channel is clean; frequency hopping will use this channel.
- Unused — channel has interference; frequency hopping will skip this channel.
The channel map is represented as a 10-byte (80-bit) bitmap where bit n corresponds to channel n. A bit value of 1 means the channel is used; a bit value of 0 means it is unused. Bit 79 (the last bit) is always set to 0 as it is reserved.
The channel map is updated continuously based on information gathered by both the Master and the Slaves about the quality of each channel. The criteria for marking a channel as unused typically include:
- Persistent packet errors observed on a specific channel.
- Channel quality reports received from Slaves (via LMP PDUs).
- Co-existence information from the host (e.g., Wi-Fi channel in use).
4. AFH LMP PDU Exchange
AFH is always enabled by the Master after a connection is established. The channel map is maintained and communicated between the Master and Slave using Link Manager Protocol (LMP) PDUs. LMP PDUs are exchanged between the Link Manager layer of the Master and the Link Manager layer of the Slave.
Three key LMP PDUs are used for AFH:
| LMP PDU | Direction | Purpose |
|---|---|---|
| LMP_CHANNEL_CLASSIFICATION_REQ | Master → Slave | Master requests the slave to periodically report channel quality information (good / bad / unknown). |
| lmp_channel_classification | Slave → Master | Slave reports the classification of each channel (good / bad / unknown) to the Master. Sent periodically if supported. |
| LMP_SET_AFH | Master → Slave | Master sends the updated channel map to the Slave so that both devices use the same set of active channels for hopping. |
HOST (Master Side) MASTER (Link Manager) SLAVE (Link Manager)
| | |
| | |
| [Connection Established] | |
| | |
| |--- LMP_CHANNEL_CLASSIFICATION_ --->|
| | REQ PDU |
| | (Requests periodic channel |
| | quality reporting from slave) |
| | |
| | |
| |<-- lmp_channel_classification -----|
| | (Slave reports each channel |
| | as: GOOD / BAD / UNKNOWN) |
| | |
| | [Master updates its internal |
| | channel map based on slave |
| | report + its own observations] |
| | |
| | |
| |--- LMP_SET_AFH PDU --------------->|
| | (Updated channel map bitmap |
| | marking each channel |
| | as USED or UNUSED) |
| | |
| | |
| [Both devices now hop only on channels marked as USED] |
| | |
| | ... time passes ... |
| | |
| |<-- lmp_channel_classification -----|
| | (Slave reports updated |
| | channel quality) |
| | |
| | [Master updates channel map] |
| | |
| |--- LMP_SET_AFH PDU --------------->|
| | (New channel map distributed |
| | to slave periodically) |
| | |
5. AFH in a Piconet
In a piconet (one Master + up to seven active Slaves), it is possible that the Master enables AFH for connections with some Slaves but disables it for others. This can occur when some Bluetooth Slaves support older Bluetooth versions (prior to v1.2) that do not support AFH, while other Slaves support Bluetooth v1.2 or later (which introduced AFH support).
+-------------------+
| MASTER |
| (Bluetooth v1.2) |
| Channel Map held |
| here |
+--------+----------+
|
+------------------+------------------+
| | |
+--------+-------+ +-------+--------+ +------+---------+
| SLAVE A | | SLAVE B | | SLAVE C |
| (BT v1.2+) | | (BT v1.2+) | | (BT v1.0/1.1) |
| AFH ENABLED | | AFH ENABLED | | AFH DISABLED |
| Uses channel | | Uses channel | | Uses all 79 |
| map from | | map from | | channels |
| Master | | Master | | (no AFH) |
+----------------+ +---------------+ +----------------+
Note: Master maintains separate AFH state per connection.
Slaves A and B receive LMP_SET_AFH with the channel map.
Slave C (older device) does not support AFH; hopping continues
on all 79 channels for that connection only.
6. Master and Slave Roles in a Piconet
As described in the piconet section: a piconet consists of one Master and up to seven active Slaves. All devices in the piconet are synchronized to a common clock and frequency hopping pattern. This synchronization reference is provided by the Master only.
When a device wants to connect with another device, it initiates the connection procedure. By default, the device that initiates the connection becomes the Master, and the other device becomes the Slave.
| Attribute | Master | Slave |
|---|---|---|
| Clock Reference | Provides the piconet clock that all devices synchronize to | Synchronizes its clock to the Master’s piconet clock |
| Hopping Pattern | Defines the frequency hopping sequence (based on Master BD_ADDR and clock) | Follows the hopping pattern defined by the Master |
| Channel Map (AFH) | Maintains the channel map and distributes it to Slaves | Reports channel quality; uses channel map received from Master |
| Connection Initiator | By default, the device that initiates the connection | By default, the device that accepts the connection |
7. Role Switch
Bluetooth provides an option where the Slave can become the Master by performing a role switch. The procedure to swap the roles of two devices connected in a piconet is called a role switch. The role switch can happen either:
- During the connection establishment phase, or
- After the connection has already been established.
A role switch is initiated using the HCI_Switch_Role command. HCI (Host Controller Interface) commands are sent by the Host to the Controller over the HCI interface to request the Controller to take a specific action. Either of the two connected devices can initiate the role switch.
HOST (Initiating Side) CONTROLLER A CONTROLLER B
| (Current Master) (Current Slave)
| | |
|--- HCI_Switch_Role ---->| |
| Command | |
| (Requesting | |
| role switch) | |
| | |
| |<-- LMP_slot_offset ------|
| | (Slave informs |
| | its slot offset to |
| | synchronize timing |
| | for the switch) |
| | |
| |<-- LMP_switch_req -------|
| | (Current Slave |
| | requests role swap) |
| | |
| |--- LMP_accepted -------->|
| | (Master accepts |
| | the role switch) |
| | |
| | |
| [At the agreed switch instant (FH sync point), roles are swapped]
| | |
| | |
| NEW SLAVE NEW MASTER
| (former Master) (former Slave)
| | |
|<-- HCI_Role_Change -----| |
| Event | |
| (Role switch | |
| complete) | |
| | |
Note: Either device can trigger role switch by issuing HCI_Switch_Role command.
The Slave always sends LMP_slot_offset and LMP_switch_req to the Master.
Both devices re-synchronize to the new Master's clock after the switch.
Role Switch — Step-by-Step Summary
- The Host of the device wishing to initiate the role switch sends an HCI_Switch_Role command to its Controller over the HCI interface.
- The current Slave sends an LMP_slot_offset PDU to the Master, providing timing information needed to synchronize the role switch at a precise frequency hopping boundary.
- The current Slave sends an LMP_switch_req PDU to the Master, formally requesting the role swap.
- The current Master acknowledges by sending LMP_accepted back to the Slave.
- At the agreed switch instant (a frequency hopping synchronization point), the roles are swapped. The former Slave becomes the new Master and the former Master becomes the new Slave. The new Master’s Bluetooth clock now drives the piconet.
- The Controller notifies the Host via an HCI_Role_Change event, confirming that the role switch is complete.
8. Summary
| Feature | Bluetooth Classic (BR/EDR) | Bluetooth Low Energy (BLE) |
|---|---|---|
| AFH | ✓ Supported (v1.2+), 79 channels | ✓ Supported (called LE channel map), 37 data channels |
| Role Switch | ✓ Supported via HCI_Switch_Role | ✗ Not supported (roles are fixed per connection) |
| Piconet Size | 1 Master + up to 7 active Slaves | 1 Central + multiple Peripherals (no hard limit of 7) |
All courses on EmbeddedPathashala are completely free. Explore our full curriculum on Bluetooth/BLE, Linux Kernel Programming, and Embedded Systems.
