> ## Content Index
> Fetch the complete content index at: https://novelbits.io/llms.txt
> Use this file to discover other available public pages before exploring further.

# Your Advertising Interval Is Not Your Advertising Period
- URL: https://novelbits.io/bluetooth-le-advertising-interval-vs-period/
- Published: 2026-09-07T12:01:25.000Z
- Updated: 2026-09-07T12:01:25.000Z
- Description: You set your advertising interval to 100 milliseconds. Your device is not advertising every 100 milliseconds, and it never was. Here is what the specification actually mandates, what it costs you in a power number, and the three things to do about it.
- Author: Mohammad Afaneh
- Tags: Bluetooth LE, Ultra Low Power, nRF54L15, Advertising

You set your advertising interval to 100 ms. You flashed the device, put it on a power analyzer, and now you want to know what it costs you per hour.

So you do the obvious thing. Call it 10 [advertising events](https://novelbits.io/bluetooth-low-energy-advertisements-part-1/) per second, some amount of charge per event, multiply, done.

Except your device isn’t advertising every 100 ms, and it never was. On my bench, the same firmware configured for exactly 100.0 ms advertised at an average of **105.075 ms**, and no two captures agreed. That’s not a bug in my setup, and it isn’t a quirk of the chip I happened to use. The Bluetooth specification requires it.

It doesn’t show up as an obvious failure. It shows up as a 5% error in a number that looks perfectly reasonable.

In this post, we’ll cover:

- What the specification actually mandates (and what it pointedly doesn’t)
- Why your measured period always runs long
- What that does to an average current figure, and the comparison where it does nothing at all
- How to read your real period off a capture
- Three things to do about it

## What the specification says

The relevant text lives in the Core Specification, Volume 6, Part B, Section 4.4.2.2.1, and it defines the advertising event timing like this:

```
T_advEvent = advInterval + advDelay
```

`advInterval` is the value you configured. `advDelay` is a pseudo-random value that the Link Layer generates fresh **for every advertising event**, and the specification bounds it to **0 to 10 ms**.

A few things to note.

First, it isn’t optional and there’s no standard way to switch it off. There’s no bit in the specification that disables it, and the host API doesn’t expose a knob for it.

Some controllers do offer a vendor-specific escape hatch (Nordic’s SoftDevice Controller has a Host Controller Interface (HCI) command, `hci_vs_sdc_set_adv_randomness()`, whose `rand_us`field is documented as “maximum random delay in microseconds, 0 to disable randomness”). Using it puts you outside what the specification requires, so treat it as a deliberate choice rather than a default. Assume the delay is there unless someone removed it on purpose.

Second, it applies per event, not per advertising session. Your first event might carry 3 ms of delay, the next 9 ms, the next half a millisecond. There’s no pattern to lock onto.

Third, and this is the part that surprises people, it doesn’t apply everywhere. The specification scopes it to all undirected advertising events and to connectable directed advertising events used in a *low* duty cycle mode. High duty cycle connectable directed advertising is excluded, which makes sense given that mode exists precisely to reconnect fast.

### What the specification carefully does not say

Two omissions matter here, and both of them get papered over in practice.

**It never says the delay is uniformly distributed.** It says pseudo-random, and it fixes the range. That’s all. So the moment you write “the expected value is 5 ms,” you’ve made an assumption the specification didn’t define. I’ll come back to this, because the assumption turns out to be a good one on the silicon I tested, and I did test it.

**Section 4.4.2.2.1 states the requirement without giving a reason for it**, which is why you’ll see the rationale asserted more confidently than it’s actually written. The specification does give one, though, a whole volume away: Volume 1, Part A, Section 3.3.2.2.2 says the advertising events “occur at regular intervals which are slightly modified with a random delay to **aid in**interference avoidance.” Cite that section if you need it, and keep the “aid in,” because the specification never claims the mechanism prevents collisions. It only says it helps.

## What it does to the advertising period

Let’s put numbers on it. If we assume the delay is uniform across 0 to 10 ms, its expected value is 5 ms, a nominal 100 ms interval should produce an expected period of about 105 ms, and your advertising rate isn’t 10 events per second, it’s about 9.52.

On the bench, that looked like this. The firmware is a non-connectable, non-scannable beacon (`ADV_NONCONN_IND`) with the minimum and maximum advertising interval both set to 160 units, which is exactly 100.0 ms. Setting minimum equal to maximum matters: the controller is free to pick anywhere inside the range you give it, so pinning the two together removes that freedom and leaves `advDelay` as the only thing moving. The specification recommends against equal values, so the controller can schedule around its other radio activity, which makes this a deliberate measurement choice rather than a default. A controller may schedule around the pin anyway, and one that doesn’t support the value you pinned will reject the command outright.

Across 10 captures of 30 advertising events each:

| Quantity                          | Value               |
| --------------------------------- | ------------------- |
| Configured interval               | 100.0 ms            |
| Measured mean period, 10 captures | **105.075 ms**      |
| Range across those 10 captures    | 104.25 to 106.42 ms |
| Excess over nominal               | **5.075%**          |

That’s within a tenth of a millisecond of the 105 ms a uniform assumption predicts. And it isn’t a fluke of one session: a separate run two weeks earlier, on the same silicon, landed at 105.05 ms. I also checked whether those delays were spread evenly across the 0 to 10 ms window instead of bunching up at one end. Across 200 of them, they were.

So the uniformity assumption holds here. Note carefully what that is and isn’t: it’s a **measured property of one controller**, on one system on chip (SoC), at one SDK version, at one interval. It is not something the specification promises you, and a different vendor’s controller is entitled to distribute that delay however it likes inside the range.

Now let’s look at the range in that table. Those 10 captures are identical in every respect (same firmware image, same board, same supply, same session). The period still moved by more than 2 ms between them, because each capture drew its own fresh set of random delays.

## The part that hits your power number

The charge your device spends on one advertising event is roughly fixed. It wakes, ramps the radio, transmits on three channels, and goes back to sleep. What varies is how often that happens.

Average current from advertising is approximately the charge per event divided by the period. So if you predict average current using the interval you configured while your device actually runs at 105.075 ms, you overestimate the advertising contribution by **5.075%**. The general form is easy to carry around, so let’s write it down: the error is roughly 5 ms divided by your advertising interval. That 5 ms is the uniform assumption again, so the rows below inherit it, and on a controller you haven’t characterized they are an estimate rather than an exact figure.

| Advertising interval              | Overestimate if you use the nominal |
| --------------------------------- | ----------------------------------- |
| 20 ms (the specification’s floor) | **\~25%**                           |
| 50 ms                             | \~10%                               |
| 100 ms                            | \~5%                                |
| 500 ms                            | \~1%                                |
| 1 s                               | \~0.5%                              |
| 10 s                              | \~0.05%                             |

The top row is the one to remember, and it isn’t only arithmetic. In a separate session on the same part, a configured 20 ms advertised at 25.166 ms across 254 intervals, which is the quarter the table predicts. The mean delay there came out at 5.17 ms against 5.05 ms at 100 ms, so the delay does not scale with the interval, and that is exactly why its relative cost climbs as the interval falls. The specification fixes that range without fixing its average, so a controller whose delays cluster high could push a 20 ms interval to 50%. That is the ceiling the specification allows; a quarter is what this controller did. It falls away quickly above 20 ms, and somewhere around a second you can stop thinking about it.

Nordic teaches the same correction, if you want a second source before you trust it. In *Designing Low-Power Bluetooth LE Products*, Lesson 3’s advertising exercise extrapolates average current by dividing the event charge by [1005 ms for a 1000 ms interval, and by 105 ms for a 100 ms one](https://academy.nordicsemi.com/courses/designing-low-power-bluetooth-le-products/lessons/lesson-3-tools-and-best-practices-for-power-measurement/topic/exercise-2-bluetooth-le-advertising-power-profiling-and-data-extrapolation/?ref=novelbits.io), and it spells out that the delay lands on every interval regardless of length, so a configured 20 ms converges to 25 ms.

🔋 

**Need this on your own hardware?** A 5% period error is easy to catch once you know to look for it. The drains that actually shorten a battery are quieter: a sleep floor that is not where you think it is, stray wake-ups, an advertising interval that is not the one you configured. Finding those means measuring the device doing its real work, which is what the [Bluetooth LE power and battery-life work](https://novelbits.io/consulting/#power) is for. 

It also runs in the direction people find least intuitive. Your calculation says the device costs more than it does, so your battery life estimate comes out short, which is the conservative direction, so nobody investigates it. The error just sits there.

And there’s a second, sneakier version. If you capture a fixed window of time and divide by the number of events you *think* it contains, you’re making the same mistake with extra steps. For a free-running advertiser, a 20 s capture at a nominal 100 ms doesn’t hold 200 events; it holds about 190\. (If your firmware sets a fixed event count, which some beacon samples do, then none of that arithmetic applies at all and the count is simply whatever you asked for.)

### Where it does nothing, which is most of the time

Here is the part I got wrong in my first draft.

**A systematic offset cancels out of a comparison.** If you’re testing two firmware builds against each other, both at 100 ms, both carry the identical period factor, and it divides out of the ratio exactly. A 2% improvement measures as a 2% improvement whether you use 100 ms or 105.075 ms in the denominator. The offset does not eat your comparison, and it doesn’t eat half of it either.

It survives a little better when you compare two *different*intervals, but only a little. Going from 100 ms to 110 ms looks like a 9.09% saving on nominal figures and is really an 8.69% saving, so the delay accounts for 0.4 of a percentage point, or about **4.4% of the saving**. It’s worth knowing, but it isn’t the headline.

**What actually threatens a small comparison is the random half, not the systematic one.** The run-to-run period spread I measured was 0.646%. Compare two captures and both of them carry it, so the difference between them carries more: **0.914%**. Against the 2% improvement you were hoping to detect, that’s **46% of your signal**, sitting there as noise, on a bench where nothing changed.

So the fix is to count more events, not to buy a better meter.

## Why repeated measurements disagree

That scatter is predictable, and it is worth knowing where it comes from.

Every event draws its own delay, so no two captures ever see the same set of them. Averaging across a capture pulls most of that out, but not all of it, and what’s left is why 10 identical captures gave me 10 different periods. I measured that run-to-run spread at **0.646%**, and `advDelay` accounts for most of it.

**Capture more events and the scatter shrinks: four times as many events, half the scatter.** Going from 30 events to 120 does exactly that.

**A better power analyzer does nothing for it**, because the variation was never in your instrument.

The size of that scatter is also a diagnostic. From one event to the next the spacing moves by around **2.9 ms**, and that figure doesn’t change when you change your interval, so the scatter you measure tells you what you’re actually looking at:

- Land near 2.9 ms and your interval is pinned and you’re seeing pure `advDelay`.
- Land far above that and something other than `advDelay`is moving the advertising period.
- Land near zero and the randomization isn’t being applied.

That last one has a deliberate cause (the vendor command above) and, on Nordic’s SoftDevice Controller, an accidental one: known issue DRGN-29306, where an advertising set that has previously run a high duty cycle directed advertiser stops applying the random delay to its undirected events, and stopping or restarting the set doesn’t bring it back. Nordic’s documented way out is to call that same vendor command with `rand_us` set to 10000, or to recreate the advertising set.

## How to actually read the advertising period

Let’s get concrete about where this number comes from, because “measure the advertising period” is easy to say and slightly less obvious to do.

![A power capture of an nRF54L15-DK advertising non-connectably, zoomed to the 3.04 second burst that holds all 30 advertising events. Dashed lines mark the first and last event, with the span between them labeled, and two lines compare dividing that span by 29 intervals against dividing it by 30 events.](https://storage.ghost.io/c/86/70/8670d5a8-12b7-448c-b3db-a85bc1fcdea7/content/images/2026/08/2026-08-19-advdelay-capture-structure-1.png)

One of the 10 captures behind that table, zoomed to the 3.04 s that holds all 30 advertising events. Measuring first event to last and dividing by the 29 gaps gives 104.85 ms for this capture; dividing by 30 events instead gives 101.36 ms. Source: PPK2 capture, nRF54L15-DK at 3.0 V, 100 kS/s, 2026-08-18.

On a power capture, the advertising events are the tall, narrow bursts and they’re unmistakable. What you want is the time from the start of one burst to the start of the next, averaged over as many as your capture holds. Don’t measure a single gap and call it the advertising period (a single gap contains a single random draw and tells you almost nothing). Take the first and last event, subtract, and divide by the number of intervals between them, which is one less than the number of events.

That last detail catches people. A 30 event capture has 29 gaps. Divide by 30 instead and the advertising period comes out about **3.3%** low.

Now let’s notice which direction each error runs. The advertising delay pushes our measured period **up** by 5.1%. The off-by-one pushes it **down** by 3.3%. Make both mistakes at once and we get 101.6 ms, which is close enough to the 100 ms you configured that you’ll conclude the measurement confirms the datasheet, write it down, and move on.

Both errors are big enough to matter on their own, and together they cancel into an answer that looks fine.

If you’re working from a sniffer capture instead, group the packets into events before you do any of this. Nordic’s nRF Sniffer has a single radio, so it listens to one channel at a time. By default it waits on channel 37, and each time it catches a packet it hops to the next one, 38, then 39, then back to 37\. A single advertising event transmits on all three in quick succession, so that hop pattern means one event can appear as up to three timestamped packets a millisecond or two apart, followed by the \~105 ms gap you actually care about. Divide by the packet count instead of the event count and you’ll get a period around a third of the real one, which is the same denominator mistake this post exists to prevent.

Either way, write the number down next to the measurement it belongs to. A period belongs to the capture it came from, not to your firmware, so reusing yesterday’s number is its own version of this mistake.

## Three things to do about it

**Measure the advertising period, don’t assume it.**Every power capture that shows you advertising events also shows their spacing, and every sniffer capture timestamps them. The number takes about 10 s to obtain and it isn’t the number in your configuration file.

**Normalize by the measured period when you compare.**Every capture draws its own set of random delays, whether or not it shares a session with the one you’re comparing it against, so this applies as much to two builds captured 10 minutes apart as to two captured on different days. The systematic part already cancels when both sides sit at the same interval, so that isn’t what normalizing buys you. What it buys you is the period’s share of the run-to-run scatter. Whatever else your bench contributes is still there afterward, so treat this as removing one known term, not as making two captures interchangeable.

**Average enough events that the delay stops mattering.** If you want the period’s contribution below 0.2%, you need roughly 200 intervals, which at a measured 105 ms is about 21 s of capture. That is cheap.

One thing I don’t recommend: correcting for it analytically by adding 5 ms and moving on. The expected value is 5 ms, but any individual capture isn’t the expected value, and the variation is as much of a problem as the offset.

## Where this doesn’t apply

A few boundaries, so you don’t over-apply this.

**Periodic advertising is the way out, for the periodic train.** If you need a deterministic broadcast interval, this is the mode that gives it to you: the periodic train carries no 0 to 10 ms random delay, which is what lets a scanner wake in a narrow window instead of listening wide. One thing to watch on a power capture, though: the [extended advertising](https://novelbits.io/bluetooth-5-advertisements/) set that announces the train is an ordinary advertising set, and its primary channel events still carry `advDelay`. You’ll see two rhythms, and only one of them is jitter free.

**Connections don’t work this way.** Once a connection is established, connection events are anchored to the [connection interval](https://novelbits.io/ble-connection-intervals/), and the timing behavior you care about is window widening driven by clock accuracy. The mechanism is different, and so is the math.

**High duty cycle directed advertising is excluded**, as above.

**Extended advertising changes the packet structure**and therefore the energy per event, though the interval mechanism still applies to the primary channel events. The period reasoning here holds, but every number about charge per event needs re-deriving for your configuration.

**Your controller may be moving the interval too.** I removed that deliberately by pinning minimum and maximum to the same value. If yours differ, the specification lets the controller choose a value inside that range (the HCI parameters are documented as a range precisely so it can pick one that fits its other scheduling), so your baseline period may not be the minimum you asked for. Check your configuration before you attribute everything you see to `advDelay`.

## Summary and closing

In this post, we covered why your advertising period is never the advertising interval you configured, and what that does to a power measurement.

We covered:

- The Core Specification mandates a pseudo-random `advDelay` of 0 to 10 ms per advertising event, so `T_advEvent = advInterval + advDelay`
- It applies to undirected advertising and to low duty cycle connectable directed advertising, and there’s no standard way to disable it (vendor-specific commands and periodic advertising are the exceptions)
- The specification fixes the range but never the distribution; assuming uniform predicts 105 ms at a 100 ms interval, and on the controller I measured that assumption held (105.075 ms, and 105.05 ms in a separate session)
- Predicting average current from the configured interval overestimates the advertising contribution by roughly 5 ms divided by your interval, about 25% at the 20 ms floor, 5% at 100 ms, and negligible by 1 s, where that 5 ms assumes a uniform draw of the kind I measured
- That offset **cancels** out of a same-interval comparison; what threatens a small comparison is the random part, which is 46% of a 2% signal
- Run-to-run variation shrinks as you capture more events, so more events fixes it and better instruments don’t

You should now be able to look at a power capture, tell how much of what you’re seeing is your device and how much is the protocol, and set up a comparison between two builds that isn’t quietly biased before you start.

That raises a further question: once you’ve removed the protocol’s contribution, how repeatable is what remains? That’s a measurement about your bench rather than about Bluetooth LE, and it’s worth its own post.