How to Use BLE Long Range (Coded PHY)

Your asset tracker worked flawlessly during testing: clean telemetry, solid connections, textbook performance. Then you deployed it across a 400-meter warehouse, and half your devices went silent. You cranked TX power to the maximum. Maybe 20 meters more. You added a better antenna. Another 30 meters. You’re still 150 meters short, and now you’re wondering if you need to abandon BLE entirely for LoRa or Zigbee.
Before you rearchitect your entire stack, there’s a BLE-native solution you probably haven’t implemented yet: BLE Coded PHY. It’s been in the Bluetooth spec since version 5.0, it can extend your range to 300-500 meters in industrial environments (sometimes further), and it requires surprisingly little code to enable. This guide walks you through the implementation on Nordic nRF platforms, with code you can adapt today.
What Coded PHY Actually Changes
Standard BLE uses 1M PHY: one symbol per bit, no redundancy. Coded PHY adds forward error correction (FEC) by encoding each bit into multiple symbols. The receiver can reconstruct the original data even when some symbols are corrupted by noise or interference.
Two coding schemes exist:
- S=2: Each bit encoded as 2 symbols. Doubles transmission time, improves sensitivity by ~5 dB.
- S=8: Each bit encoded as 8 symbols. 8x transmission time, improves sensitivity by ~12 dB.
That sensitivity improvement translates directly to range. The link budget math: every 6 dB roughly doubles your range. S=8 gives you approximately 4x the range of 1M PHY under the same conditions.
| Metric | 1M PHY | Coded PHY (S=2) | Coded PHY (S=8) |
|---|---|---|---|
| Data rate | 1 Mbps | 500 kbps | 125 kbps |
| Sensitivity gain | Baseline | +5 dB | +12 dB |
| Typical range (open field) | 100-200m | 200-400m | 400m-1km+ |
| Realistic industrial range | 50-100m | 100-250m | 200-500m |
| TX time per byte | 8 µs | 16 µs | 64 µs |
Critical point: Longer range doesn’t automatically mean better battery life. You’re transmitting for 8x longer with S=8, which means 8x the energy per packet. The battery wins come from needing fewer retransmissions at distance and from sleeping longer between successful transmissions.
Hardware Requirements
Not all BLE chips support Coded PHY. On the Nordic side:
- nRF52840: Full Coded PHY support (S=2 and S=8)
- nRF5340: Full support
- nRF52833: Full support
- nRF52832: No Coded PHY support. If this is your current chip, you need a hardware change.
Both devices must support Coded PHY. Your long-range peripheral is useless if your gateway runs on an nRF52832 or a phone with a chipset that doesn’t support it. Most modern Android phones (2019+) and iPhones (iPhone 8+) support Coded PHY as centrals, but verify your specific gateway hardware.
For antenna selection in industrial environments, prioritize gain over form factor if you can. A PCB antenna might work fine in the lab but struggle against metal structures. Whip antennas or external ceramic antennas provide meaningful improvement in RF-harsh settings.
Enabling Coded PHY for Advertising
Coded PHY requires extended advertising. The legacy advertising PDUs don’t support it. This is the most common implementation mistake: enabling Coded PHY in your config but forgetting extended advertising, then wondering why your sniffer shows standard advertising.
nRF Connect SDK Configuration
First, enable the required Kconfig options in your prj.conf:
CONFIG_BT_EXT_ADV=y
CONFIG_BT_CTLR_PHY_CODED=y
CONFIG_BT_CTLR_ADV_EXT=yAdvertising Setup Code
Here’s the Coded PHY-specific configuration for extended advertising. This assumes you already have standard BLE initialization in place:
/* Coded PHY advertising parameters */
static struct bt_le_adv_param adv_params = BT_LE_ADV_PARAM_INIT(
BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_EXT_ADV | BT_LE_ADV_OPT_CODED,
BT_GAP_ADV_SLOW_INT_MIN, /* 1s min interval - adjust for your battery budget */
BT_GAP_ADV_SLOW_INT_MAX, /* 1.2s max interval */
NULL /* Undirected advertising */
);
static struct bt_le_ext_adv *adv_set;
int start_coded_phy_advertising(void)
{
int err;
/* Create advertising set with Coded PHY parameters */
err = bt_le_ext_adv_create(&adv_params, NULL, &adv_set);
if (err) {
printk("Failed to create advertising set (err %d)\n", err);
return err;
}
/* Set your advertising data here using bt_le_ext_adv_set_data() */
err = bt_le_ext_adv_start(adv_set, BT_LE_EXT_ADV_START_DEFAULT);
if (err) {
printk("Failed to start advertising (err %d)\n", err);
return err;
}
printk("Coded PHY advertising started\n");
return 0;
}Common Pitfall: If you omit
BT_LE_ADV_OPT_EXT_ADV, the stack may silently fall back to legacy advertising on 1M PHY. Always verify your PHY with a sniffer or nRF Connect for Mobile.
For battery-powered asset trackers, advertising interval matters enormously. The example above uses 1-1.2 second intervals, which is reasonable for devices that need periodic discovery. For aggressive power savings, consider intervals of 2-10 seconds, accepting longer discovery times. See our guide on BLE advertising interval vs battery life modeling for detailed power calculations.
Applying to Other Platforms
The concepts translate directly to other vendor SDKs. You need extended advertising enabled, Coded PHY selected as the primary PHY, and the controller compiled with Coded PHY support. The specific API calls differ:
- Silicon Labs Gecko SDK: Use
sl_bt_advertiser_set_phy()withsl_bt_gap_phy_coded - TI SimpleLink: Configure
GapAdv_setParam()withGAP_ADV_PRIM_PHY_CODED_S8 - ESP32 (ESP-IDF): Set
primary_phyandsecondary_phytoBLE_HCI_LE_PHY_CODEDin extended advertising parameters
If you’re working with a different SDK and need implementation help, reach out to our team.
Enabling Coded PHY for Connections
Advertising gets you discovered. For ongoing communication with your asset tracker, you’ll want Coded PHY connections. The BLE spec requires that connections start on 1M or 2M PHY, then negotiate to Coded PHY via a PHY update procedure.
Kconfig for Connection PHY Support
Add to your prj.conf:
CONFIG_BT_USER_PHY_UPDATE=y
CONFIG_BT_AUTO_PHY_UPDATE=n /* We'll control this explicitly */PHY Update Code
Request the PHY update after connection establishment:
static void request_coded_phy(struct bt_conn *conn)
{
int err;
/* Request Coded PHY (S=8 for maximum range) */
const struct bt_conn_le_phy_param phy_params = {
.options = BT_CONN_LE_PHY_OPT_CODED_S8,
.pref_tx_phy = BT_GAP_LE_PHY_CODED,
.pref_rx_phy = BT_GAP_LE_PHY_CODED,
};
err = bt_conn_le_phy_update(conn, &phy_params);
if (err) {
printk("PHY update request failed (err %d)\n", err);
}
}
/* Callback for PHY update completion */
static void phy_updated(struct bt_conn *conn,
struct bt_conn_le_phy_info *param)
{
printk("PHY updated: TX PHY %u, RX PHY %u\n",
param->tx_phy, param->rx_phy);
/* Verify we got Coded PHY */
if (param->tx_phy == BT_GAP_LE_PHY_CODED) {
printk("Coded PHY active - long range enabled\n");
} else {
printk("Warning: Coded PHY not negotiated, using %u\n", param->tx_phy);
}
}
/* Register the callback in your connection callbacks struct */
BT_CONN_CB_DEFINE(conn_callbacks) = {
.connected = connected,
.disconnected = disconnected,
.le_phy_updated = phy_updated,
};Fallback handling: If the central doesn’t support Coded PHY, the update request will complete successfully but report 1M or 2M PHY. Your firmware should handle this gracefully. Don’t assume Coded PHY is active just because you requested it. Check the callback parameters.
For remote asset tracking where updates are infrequent (position reports every few minutes), use long connection intervals. A 4-second connection interval with 5-second supervision timeout lets your tracker sleep extensively while maintaining the connection for on-demand queries.
Industrial Asset Tracking: Practical Considerations
Datasheets quote 1km+ range for Coded PHY. Real industrial environments deliver 200-500 meters. The difference: metal structures, RF interference from machinery, multipath reflections, and non-line-of-sight paths. Our analysis of BLE range marketing claims vs real-world results explains why these gaps exist across all BLE implementations.
Plan for 300 meters as a reliable working range in typical warehouses and manufacturing floors. Test in your actual environment. RF propagation is site-specific, and a quick field test tells you more than any calculation. If you’re seeing unexpectedly poor performance, check our guide on BLE coexistence with WiFi and other 2.4GHz systems for interference troubleshooting.
Hybrid PHY Strategy
Consider a hybrid approach for asset tracking deployments:
- Near gateway (< 100m): Use 1M PHY for faster data transfer and lower power per packet
- Distant assets (> 100m): Use Coded PHY for reliability
Implementation: Start with 1M PHY advertising. If connection fails or RSSI drops below a threshold (-85 dBm is a reasonable starting point), switch to Coded PHY. This optimizes battery life for assets that spend time near gateways while maintaining connectivity for distant ones.
Duty Cycle for Battery Life
Asset trackers don’t need continuous connectivity. A typical industrial pattern:
- Advertise for 5 seconds every 5 minutes (discovery window)
- When connected, report position, then request disconnect
- Sleep between advertising bursts
With this pattern, a 500mAh battery can last 12+ months even with Coded PHY’s higher TX energy. The math favors infrequent successful transmissions over frequent failed ones.
Testing and Validation
Before field deployment, verify Coded PHY operation:
nRF Connect for Mobile: Connect to your device, navigate to the connection details. It displays the active PHY. Verify it shows “LE Coded” rather than “LE 1M.”
RSSI logging: Walk your intended coverage area while logging RSSI. Coded PHY should maintain connection 2-4x further than 1M PHY showed. Mark where you lose signal. That’s your real coverage boundary.
Packet error rate: At range boundary, monitor connection stability. Coded PHY’s FEC should maintain clean connections well past where 1M PHY shows dropped packets.
Building Long Range Into Your Deployment
Coded PHY is the straightforward answer when you need more BLE range without switching protocols. The implementation is minimal (a few Kconfig options and API calls), but the architectural decisions matter: choosing appropriate advertising intervals, handling PHY negotiation fallbacks, and designing sleep patterns that exploit the lower retransmission rates.
Start with the code examples above, get them running on your nRF52840 or nRF5340 dev kit, then test in your target environment. Your 400-meter warehouse that silenced half your trackers? It’s solvable without abandoning your BLE investment.
For deeper optimization (power profiling, antenna selection, or adapting these patterns to non-Nordic platforms), we cover those in related guides, or you can contact our team directly for implementation support.
Hubble connects directly to BLE devices from space—no gateways, no infrastructure changes. See how it works →