Physical Layer (PHY)

Introduction

The physical layer (PHY) is the lowest layer of the Bluetooth low energy protocol stack. It configures the physical parameters of the radio transmission and reception. It determines how a bit (and its value) are represented over the air. By switching the PHY, the physical properties of the RF signal is changed.

The supported PHYs include LE 1M, 2M, and Coded PHY. All the projects in BLE5-Stack have support for all of these PHYs; APIs need to be called in the application to utilize the feature.

The following HCI commands were added to support this feature:

When the HCI_LE_SetPhyCmd() is called, the controller starts the PHY Update Procedure to change the PHYs. The procedure consists of exchanging the PHY preferences of both devices and negotiating the correct PHY to use based on the PHY preferences. Depending on peer device capability and preference(s), the PHY Update Procedure may not result in a change to the active PHY configuration.

LE 2M PHY

The BLE5-Stack supports transferring data over the mandatory symbol rate of 1 megasymbol per second (Msym/s) where 1 symbol represents 1 bit. This results in a bit rate of 1 megabit per second (Mb/s), which is referred to as LE 1M PHY.

The stack also supports an optional symbol rate of 2 Msym/s, with a bit rate of 2 Mb/s, which is referred to as LE 2M PHY.

LE Coded PHY

LE Coded PHY allows the ability to have the signal range increase up to nearly quadruple the range of LE 1M PHY. This is achieved by coding the signal, so the Tx power stays the same. This means that the power consumption per time stays the same. On the other hand, this coding entails a lower data throughput.

LE Coded S2 and S8

The LE Coded PHY can be operated with two data rates:

  • S2 : In LE Coded S=2 mode, each bit is represented by two symbols. Thus, the data rate is 500kbps. In this mode the range is roughly doubled compared to the LE 1M PHY.

  • S8: In LE Coded S=8, each bit is represented by eight symbols. This gives a data rate of 125kbps. In this mode the range is roughly quadrupled compared to the LE 1M PHY.

Every packet sent on LE Coded PHY contains a coding indicator (CI), which indicates the coding of the packet. Thus, when a packet is being received on the LE Coded PHY, the receiver uses the coding indicator to determine the coding of the packet. The full packet format of packets sent on LE Coded PHY is found in the Bluetooth Core Specifications Version 5.2, Vol 6, Part B, Chapter 2.2 PACKET FORMAT FOR THE LE CODED PHY.

PHY Comparison

A comparison of the Bluetooth Low Energy PHYs is given below:

Table 18. Comparison of the PHYs.

Parameter

LE 1M

LE 2M

LE Coded S=2

LE Coded S=8

Symbol Rate

1Msps

2Msps

1Msps

1Msps

Data Rate

1Mbps

2Mbps

500kbps

125kbps

Error Correction

None

None

FEC

FEC

Range Multiplier

1

~0.8

~2

~4

LE 2M PHY vs LE 1M PHY

The LE 2M PHY feature uses the same transmit power as the LE 1M PHY, the only change is in the modulation of data in the PHY. Using the LE 2M PHY, the energy consumption decreases due to higher data modulation at the same output power. The following table lists some of the differences between the two PHYs:

Table 19. Tradeoff between 1M and 2M PHYs

Parameter

Comparison

Power consumption

Energy consumption is reduced using the same transmit power.

Data Rate

LE 2M PHY is 2x faster to transmit data than LE 1M PHY.

Receive Sensitivity

The link budget will be lower relative to LE 1M PHY, due to the increased symbol rate.

Tramsmit Power

The output power is same for both PHYs.

The main advantage to use the LE 2M PHY is for high throughput applications to transfer data at a higher speed.

LE Coded PHY vs LE 1M PHY

The LE Coded PHY feature uses the same transmit power as the LE 1M PHY, the only change is in the modulation of data in the PHY. Using the LE Coded PHY, the energy consumption increases because the radio is in Tx longer. Thus the main application for LE Coded PHY should be applications that need a long range, but a low data rate. According to the Bluetooth spec, there are limitations on what packets can be sent on the LE Coded PHY.

Advertising PHY

We will use a snippet similar to the example application simple peripheral to show how to advertise on multiple PHYs by selecting a PHY for each advertisement set. Please use GAP Advertiser as a reference for the advertisement API s.

Set up the advertising parameters for each set and specify the PHY. The snippet provides a way to use a predefined parameter set (e.g. GAPADV_PARAMS_LEGACY_SCANN_CONN). The primary PHY and secondary PHY can also be individually selected (e.g. GAP_ADV_PRIM_PHY_CODED_S2 or GAP_ADV_SEC_PHY_CODED_S8) in the advertisement parameters:

Listing 162. Create two advertisement sets at different PHYs
 1  // Advertising handles
 2  static uint8 advHandleLegacy;
 3  static uint8 advHandleLongRange;
 4
 5  // Temporary memory for advertising parameters for set #1 (1M PHY)
 6  GapAdv_params_t advParamLegacy = GAPADV_PARAMS_LEGACY_SCANN_CONN;
 7
 8  // Create Advertisement set #1 and assign handle
 9  status = GapAdv_create(&SimplePeripheral_advCallback, &advParamLegacy,
10                         &advHandleLegacy);
11
12  // Use long range params to create long range set #2 (Coded PHY S2)
13  GapAdv_params_t advParamLongRange = GAPADV_PARAMS_AE_LONG_RANGE_CONN;
14
15  // Alternatively, set the parameters individually.
16  advParamLongRange.primPhy = GAP_ADV_PRIM_PHY_CODED_S2;
17  advParamLongRange.secPhy = GAP_ADV_SEC_PHY_CODED_S8;
18
19  // Create Advertisement set #2 and assign handle
20  status = GapAdv_create(&SimplePeripheral_advCallback, &advParamLongRange,
21                         &advHandleLongRange);

According to the Bluetooth Core Specifications Version 5.2 (Version 5.0 | Vol 6, Part B, Chapter 2.3 ADVERTISING CHANNEL PDU), only the following PDU types can be transmitted on the LE Coded PHY:

  • ADV_EXT_IND

  • AUX_ADV_IND

  • AUX_SYNC_IND

  • AUX_CHAIN_IND

  • AUX_SCAN_REQ

  • AUX_SCAN_RSP

  • AUX_CONNECT_REQ

  • AUX_CONNECT_RSP

You can read about each PDU in the Bluetooth Core Specifications Version 5.2, Vol 6, Part B, Chapter 2.3 ADVERTISING CHANNEL PDU.

The primary PHY parameter will decide whether the device is advertising in legacy mode, or in long range mode (with ADV_EXT_IND). The secondary PHY parameter will decide the PHY of any auxiliary advertisement packets (i.e. all packets beginning with AUX_).

If advertising non-connectable and non-scannable, an ADV_EXT_IND PDU with no Adv Data can be sent without an auxiliary packet. In all other cases, the ADV_EXT_IND PDU must contain a pointer to an auxiliary advertisement packet, AUX_ADV_IND. The AUX_ADV_IND PDU is sent on the PHY given in secPhy, and on one of the secondary channels (also known as data channels).

Scanning PHY

We will use a snippet similar to the example application simple central to show how the scanning PHY is selected. Please use GAP Scanner as a reference for the scanner API s.

Setup the scanner PHY parameters and the scan primary PHY (e.g. SCAN_PRIM_PHY_1M):

Listing 163. Setup scan parameters
 1  GapScan_PrimPhy_t scanPhy = SCAN_PRIM_PHY_1M;
 2  GapScan_ScanType_t scanType = SCAN_TYPE_ACTIVE;
 3  uint16_t scanInt = SCAN_PARAM_DFLT_INTERVAL;
 4  uint16_t scanWindow = SCAN_PARAM_DFLT_INTERVAL;
 5
 6  // Set Scan PHY parameters
 7  GapScan_setPhyParams(DEFAULT_SCAN_PHY, SCAN_TYPE_ACTIVE,
 8                     SCAN_PARAM_DFLT_INTERVAL, SCAN_PARAM_DFLT_INTERVAL);
 9
10  // Set scanning primary PHY
11  GapScan_setParam(SCAN_PARAM_PRIM_PHYS, &scanPhy);

To scan on multiple PHYs (e.g. SCAN_PRIM_PHY_1M and SCAN_PRIM_PHY_CODED), individual PHYs can be OR’ed together:

Listing 164. Multiple PHY scan
 1  GapScan_PrimPhy_t scanPhy = SCAN_PRIM_PHY_1M | SCAN_PRIM_PHY_CODED;
 2  GapScan_ScanType_t scanType = SCAN_TYPE_ACTIVE;
 3  uint16_t scanInt = SCAN_PARAM_DFLT_INTERVAL;
 4  uint16_t scanWindow = SCAN_PARAM_DFLT_INTERVAL;
 5
 6  // Set Scan PHY parameters
 7  GapScan_setPhyParams(scanPhy, scanType,
 8                   scanInt, scanWindow);
 9
10  // Set scanning primary PHY
11  GapScan_setParam(SCAN_PARAM_PRIM_PHYS, &scanPhy);

As noted in LE Coded S2 and S8, each packet transmitted on the LE Coded PHY contains a coding indicator that tells the receiving device what the coding of the packet is. It is thus not necessary to tell the GAP Scanner what coding to use when scanning on the LE Coded PHY.

In order to send a scan request to an advertiser which is advertising on LE Coded PHY, the scanner must listen for the AUX_ADV_IND indicated by the pointer in the ADV_EXT_IND PDU, and send a scan request to this packet. This will be an AUX_SCAN_REQ, sent on the same PHY and channel as the AUX_ADV_IND. In turn, the advertiser can send an AUX_SCAN_RSP on the same PHY and channel.

Please reference PHY Limitations if trying to use the LE 2M PHY when scanning for extended advertisements.

Initiating PHY

We will use a snippet similar to the example application simple central to show how the initiating PHY is selected. Please use GAP Initiator as a reference for the initiator API s.

Select which PHY to use when initiating the connection (e.g. INIT_PHY_CODED):

Listing 165. Initiate a connection using LE Coded PHY
1  GapInit_InitPhy_t initPhy = INIT_PHY_CODED;
2
3  GapInit_connect(scanList[index].addrType & MASK_ADDRTYPE_ID,
4                  scanList[index].addr, initPhy, 0);

To initiate on multiple PHYs (e.g. INIT_PHY_1M and INIT_PHY_CODED), individual PHYs can be OR’ed together:

Listing 166. Multiple PHY init
1  GapInit_InitPhy_t initPhy = INIT_PHY_1M | INIT_PHY_CODED;
2
3  GapInit_connect(scanList[index].addrType & MASK_ADDRTYPE_ID,
4                  scanList[index].addr, initPhy, 0);

In order to send a connection request to an advertiser which is advertising on LE Coded PHY, the initiator must listen for the AUX_ADV_IND indicated by the pointer in the ADV_EXT_IND PDU, and send a connection request to this packet. This will be an AUX_CONNECT_REQ, sent on the same PHY and channel as the AUX_ADV_IND. In turn, the advertiser can send an AUX_CONNECT_RSP on the same PHY and channel.

Changing PHY

The application can initiate a PHY Update Procedure in a connection regardless of the role of the device (Central or Peripheral). The PHY preferences that are set by HCI_LE_SetDefaultPhyCmd() are used by default during a set PHY negotiation.

Attention

Calling HCI_LE_SetPhyCmd() to change the PHY will change the preferred PHY of the device. This means that in some cases, only the device that first changed the active PHY can change it back.

When the application has finished the PHY critical operations, it is therefore a good idea to change the PHY to a bit mask with every supported PHY, e.g. (LE 1M PHY | LE Coded PHY). This will allow the peer device to change the PHY back to LE 1M.

The HCI_LE_SetDefaultPhyCmd() is used to specify the preferred PHY for transmit and receive for all subsequent connections. However, when the HCI_LE_SetPhyCmd() is used to change the PHY for the connection, the change only applies to that connection. Subsequent connections will revert to using the default PHYs.

The HCI_LE_SetDefaultPhyCmd() should be called before forming the connection and HCI_LE_SetPhyCmd() can only be called during a connection. Also note that the HCI_LE_SetDefaultPhyCmd() does not change the PHY, only the HCI_LE_SetPhyCmd() can request a change to the PHY.

The parameters for HCI_LE_SetDefaultPhyCmd() and HCI_LE_SetPhyCmd() are same. The allPhys parameter specifies whether the other two parameters (txPhy and rxPhy) are used or not. Central value of ‘1’ indicates the client has no PHY preference for that direction, while a ‘0’ indicates that the corresponding parameter should be used. The txPhy and rxPhy can be set to specify which PHY to use for transmitting and receiving, respectively. Note that when all supported PHY are specified, the stack always tries to select the fastest PHY during a set PHY negotiation.

Table 20. HCI_LE_SetPhyCmd and HCI_LE_SetDefaultPhyCmd variables.

Name

Usage

Description

HCI_PHY_USE_PHY_PARAM

allPhys

Use Phy Param

HCI_PHY_USE_ANY_PHY

allPhys

Use any PHY

HCI_PHY_1_MBPS

txPhy and rxPhy

LE 1M PHY

HCI_PHY_2_MBPS

txPhy and rxPhy

LE 2M PHY

HCI_PHY_CODED

txPhy and rxPhy

LE Coded PHY

In addition, for LE Coded PHY you can choose between S=2 and S=8 with the phyOpts parameter. Use the following API to change/set the PHY:

Listing 167. Call API to set the PHY
// Set Phy Preference on the current connection. Apply the same value
// for RX and TX.
HCI_LE_SetPhyCmd(connectionHandle, HCI_PHY_USE_PHY_PARAM, HCI_PHY_CODED, HCI_PHY_CODED, 0);

Based on the PHY negotiation, the PHY will change if the peer remote device supports the given PHY(s). Otherwise, it will continue using the current PHY. After this command is sent, the controller will send a hciEvt_BLEPhyUpdateComplete_t which will indicate completion of this command:

Listing 168. Receive PHY Update Complete event
 1static uint8_t SimplePeripheral_processStackMsg(ICall_Hdr *pMsg)
 2{
 3  ...
 4  case HCI_LE_EVENT_CODE:
 5  {
 6    hciEvt_BLEPhyUpdateComplete_t *pPUC = (hciEvt_BLEPhyUpdateComplete_t*) pMsg;
 7
 8    // A Phy Update Has Completed or Failed
 9    if (pPUC->BLEEventCode == HCI_BLE_PHY_UPDATE_COMPLETE_EVENT)
10    {
11      if (pPUC->status != SUCCESS)
12      {
13        Display_printf(dispHandle, SBP_ROW_STATUS_1, 0, "PHY Change failure");
14      }
15      else
16      {
17        // Only symmetrical PHY is supported.
18        // rxPhy should be equal to txPhy.
19        Display_printf(dispHandle, SP_ROW_STATUS_2, 0,
20                       "PHY Updated to %s",
21                       (pPUC->rxPhy == HCI_PHY_1_MBPS) ? "1M" :
22                       (pPUC->rxPhy == HCI_PHY_2_MBPS) ? "2M" :
23                        "CODED");
24      }
25      ...

In case this is not the first time a PHY change is attempted, and the controller knows that the peer device does not support the desired PHY, a HCI_LE_SET_PHY event will be received:

Listing 169. Receive PHY Update Complete event
 1static uint8_t SimplePeripheral_processStackMsg(ICall_Hdr *pMsg)
 2{
 3  ...
 4  case HCI_GAP_EVENT_EVENT:
 5  {
 6  ...
 7
 8    // HCI Commands Events
 9    case HCI_COMMAND_STATUS_EVENT_CODE:
10    {
11      hciEvt_CommandStatus_t *pMyMsg = (hciEvt_CommandStatus_t *)pMsg;
12      switch ( pMyMsg->cmdOpcode )
13      {
14        case HCI_LE_SET_PHY:
15        {
16        if (pMyMsg->cmdStatus == HCI_ERROR_CODE_UNSUPPORTED_REMOTE_FEATURE)
17        {
18           Display_printf(dispHandle, SP_ROW_STATUS_1, 0,
19                          "PHY Change failure, peer does not support this");
20        }
21
22        ....

See Host Controller Interface (HCI) for more information on receiving HCI events.

The sequence diagram below shows the use case where the Central initiates the PHY update procedure:

@startuml
hide footbox


            participant Central
            participant CentralLL
            participant PeripheralLL
            participant Peripheral


            group Establish connection
                            Central -> CentralLL: GapInit_connect()
                            note left
                                    Central (formerly known as 'Central') and Peripheral
                                    (formerly known as 'Slave') are in connection
                            end note
            end
            == LE 1M PHY ==
...

            group Change PHY
                    Central -> CentralLL: HCI_LE_SetPhyCmd()
                    note left
                            Central application initiates PHY change
                    end note
                    ...

                    CentralLL -> PeripheralLL : LL_PHY_REQ
                    PeripheralLL -> CentralLL : LL_PHY_RES
                    note left
                            Link layer messages exchanged
                    end note
                    ...
                    CentralLL -> PeripheralLL : LL_PHY_UPDATE_IND

            end
            == Change of PHY ==
...

            group Receive event
                    CentralLL -> Central : LE PHY Update Complete
                    note left
                            Application receives event from stack
                    end note
                    PeripheralLL --> Peripheral : LE PHY Update Complete
            end

@enduml

Figure 101. Sequence diagram for changing PHY by Central

Alternatively, the Peripheral can also initiate the PHY Update Procedure as well using the same API as shown below:

@startuml
hide footbox


participant Central
            participant CentralLL
            participant PeripheralLL
participant Peripheral

            group Establish connection
                            Central -> CentralLL: GapInit_connect()
                            note right
                                    Central (formerly known as 'Master') and Peripheral
                                    (formerly known as 'Slave')  are in connection
                            end note
            end
            == LE 1M PHY ==
...

            group Change PHY
                    PeripheralLL <- Peripheral: HCI_LE_SetPhyCmd()
                    note left
                            Peripheral application initiates PHY change
                    end note
                    ...

                    CentralLL <- PeripheralLL : LL_PHY_REQ
                    note left
                            Link layer messages exchanged
                    end note
                    ...
                    CentralLL -> PeripheralLL : LL_PHY_UPDATE_IND

            end
            == Change of PHY ==
...

            group Receive event
                    CentralLL --> Central : LE PHY Update Complete
                    PeripheralLL -> Peripheral : LE PHY Update Complete
                    note left
                            Application receives event from stack
                    end note
            end

@enduml

Figure 102. Sequence diagram for changing PHY by Peripheral

If the PHY does not change (for example, if the Central tries to change to a PHY not supported by the Peripheral), then only the side that initiated the PHY Update Procedure will get a hciEvt_BLEPhyUpdateComplete_t event. The other side will not receive a hciEvt_BLEPhyUpdateComplete_t event if the PHY is not changed. This is represented by dotted arrow lines in the flow charts above.

PHY Negotiation

Determining when the PHY will change can be determined by looking at the PHY preferences of both devices after the HCI_LE_SetPhyCmd() is called. If both devices prefers to use LE 2M PHY, the PHY will change to LE 2M PHY. If the PHY is changed to 2M due to Central preference of only 2M, the Peripheral cannot change the PHY back to 1M until the Central changes its PHY preference to support 1M as well. Similarly if the PHY is changed to 1M due to the Peripheral preference of only 1M, the Central will not be able to change the PHY to 2M until the Peripheral changes its PHY preference to support 2M as well.

If one device initiates change to a PHY not supported on other remote device, the initiating side will receive a hciEvt_BLEPhyUpdateComplete_t event with nonzero status indicating the change was not successful. If the PHY does not change after HCI_LE_SetPhyCmd() is called, the connection continues with the current PHY.

@startuml
hide footbox

participant Central
participant CentralLL
participant PeripheralLL
participant Peripheral

group Establish connection
    Central -> CentralLL: GapInit_connect()
                            note right
                                            Central (formerly known as 'Master') and Peripheral
                                            (formerly known as 'Slave') are in connection
                            end note
end
== LE 1M PHY ==
...

group Change PHY
  PeripheralLL <- Peripheral: HCI_LE_SetPhyCmd()
                    note left
                            Peripheral application initiates PHY change
                    end note
  ...

  CentralLL <- PeripheralLL : LL_PHY_REQ
                    note left
                            Link layer messages exchanged
                    end note
  ...
  CentralLL -> PeripheralLL : LL_UNKNOWN_RSP
  ...
  PeripheralLL -> Peripheral : LE PHY Update Complete: \n PHY Change Failure
                    note left
                            Application receives event from stack
                    end note

end
== No Change of PHY ==
...
group Consecutive PHY change attempts
  PeripheralLL <- Peripheral: HCI_LE_SetPhyCmd()
                    note left
                            Peripheral application initiates PHY change
                    end note
...
PeripheralLL -> Peripheral : LE set PHY status: \n Unsupported remote feature
                    note left
                            Application receives event from stack
                    end note
end

@enduml

Figure 103. Sequence diagram for failed changing PHY attempts.

PHY Limitations

The following are the current PHY limitations in BLE5-Stack:

  • The BLE controller does not support asymmetric connections where the connection uses different PHYs in each direction (RX and TX).