Mynewt FAQ - Bluetooth

NimBLE on nRF52840

Q: Is the nRF52840 supported by NimBLE?

A: The nRF52840 is supported, including Bluetooth 5 features.

Trigger Exactly One BLE Advertisement Immediately

Q: Is there a way to trigger exactly one BLE advertisement immediately? I basically want to use BLE as a means to advertise to a whole group of devices and it needs to be relatively time-precise. Hoping for about 1ms precision, but it’s okay if there’s a delay as long as it’s deterministic.

A: With extended advertising you can enable an advertising instance for exactly 1 advertising event but there will be some delay before controller starts advertising which depends on the level of precision. The NimBLE controller always schedules the 1st advertising event with a constant 5ms delay. However, if there are other things scheduled in the controller it may need to schedule it later so it’s not guaranteed to be deterministic. Periodic advertising is currently not supported.

Supported Bluetooth Radio Transceivers

Q: Are there any other Bluetooth radio transceivers that are supported already or anyone working on? If there is a Bluetooth radio that can be integrated using the HCI, we can use the NimBLE host? If so, I suppose we don’t need detailed specs of the Bluetooth radio?

A: You should be able to run the NimBLE host against pretty much any controller using HCI. We have a BLE controller implementation for Nordic only, but host (in theory) should work with all. More likely, it will work with 5.0 controller. For 4.x controllers it may fail on initialization since we do not check controller features - but this can be fixed as for other radio transceivers. For example, there’s NXP KW41Z which has BLE-compatible radio documented. However, NXP documentation is more or less a description of zillions of different registers so not as friendly as the one from Nordic which explains how to actually use it.

NimBLE Operational Questions

Q: Can I update firmware via BLE for multiple devices simultaneously using a single device/phone supporting Bluetooth?

A: Yes, it is possible to update several Nimble devices simultaneously from a single phone (e.g., central) as long as the central can handle all the simultaneous Bluetooth connections. You can also do it using your computer as a central with newtmgr. Just open two terminals and initiate a newtmgr image upload command in each, each to a different device. You will, however, get better overall throughput if you limit yourself to one upgrade at a time.

Q: I have the following doubts on NimBLE: The document says 32+ concurrent connections, multiple connections in simultaneous central and peripheral roles. Does that mean the “device running NimBLE” can connect to 32 different other devices like phones?

A: Yes, with one caveat: each of the 32 centrals needs to be sufficiently cooperative in choosing connection partners ( Your app might need to request different connection parameters from the centrals (using ble_gap_update_params).

Of course, you will also need to build the Mynewt image device with a configuration suitable for 32 concurrent connections (e.g., NIMBLE_MAX_CONNECTIONS=32, etc.)

blemesh Forgets All Keys on Restart

Q: Is it expected that the blemesh example forgets all the keys on restart and needs to be provisioned again? If so, how can I implement key persistence myself? Is there any API to obtain / provide mesh keys before the mesh node is started? I found bt_mesh_provision, but the comment there seems to indicate that this is not the right way to use it.

A: Mesh implementations do not persist keys at the moment. There is a plan to add it but not sure about timeline. It probably needs to be implemented inside mesh implementation so there’s no API, but if you’d like to hack something I suggest taking a look at shell.c and testing.c - there are some testing functions to add/display keys. Another area to look if you actually want to persist keys to flash is net/nimble/host/store/config/src/ble_store_config.c. This is the code that persists and restores security material for (non-mesh) Bluetooth.

L2CAP Connection

Q: I want to do an L2CAP connection, and am trying the auth-passkey command, but am not sure about the parameters psm, action, and oob. What is psm, and what is the value of that parameter in the btshell command l2cap-connect? How do I set the parameters action and oob?

A: psm stands for Protocol Service Multiplexer. You pass the psm value to either l2-cap-connect or l2cap-create-server. The parameters action and oob are just passing constant values as defined in the API.

Bitbang, BLE Mesh, BLE Advertising

Q: Is it possible to run bitbanging and BLE mesh at the same time? How about running BLE Mesh and BLE advertising at the same time?

A: It is possible to run bitbanging and BLE mesh at the same time, but the bitbanging UART takes a lot of CPU on Nordic. We’ve run it at 9600 which would probably be okay for lower rate devices, but for reliability it is recommended to run at 4800. If this is just for the console and your UART port is tied up, rtt is recommended. Take a look at Segger RTT Console for more information. However, bitbanger can be handy given limited UARTs.

You can certainly continue advertisements during connections, if you are using the GATT bearer for mesh. Mesh is also tied into the ext-adv bearer in Mynewt, which also allows for interleaving, even if you’re transmitting mesh data on advertising channels.

Extended Advertising with btshell

Q: I am using btshell for advertising with nRF52. When I use 31 bytes, mfg_data accepts the data with extended advertising. But when I use more bytes than that, mfg_data doesn’t accept it. Is 251 byte payload supported in extended advertising? How can I send more than a 251 byte payload on extended advertising?

A: You need to set the BLE_EXT_ADV_MAX_SIZE syscfg to your required value. For example:

newt target amend <your_target> syscfg=BLE_EXT_ADV=1:BLE_EXT_ADV_MAX_SIZE=1650

The default is 31 bytes, and the max is 1650.

Keep in mind that with extended advertising, you cannot set advertising data for an instance configured as scannable (e.g. advertise-configure scannable=1). Either set scan response data using advertise-set-scan-rsp command (parameters are the same as for advertise-set-adv-data) or configure the instance as non-scannable. For example, advertise-configure alone will configure the instance as non-connectable and non-scannable which means you can set advertising data. Also note that if you continue to use a scannable instance you will need to perform active scanning in order to get scan response data.

FYI, legacy advertising instances can accept both advertising and scan response data but since they use legacy PDUs the limit is still 31 bytes.

Configuring Maximum Number of Connections for blehci

Q: How do I set the maximum number of connections for the blehci example? I see there is a MYNEWT_VAL_BLE_MAX_CONNECTIONS, but I don’t know how to set it.

A: You can to set it in target settings:

newt target amend <target> syscfg=BLE_MAX_CONNECTIONS=2

and then rebuild using newt build <target>. MYNEWT_VAL_BLE_MAX_CONNECTIONS is just a symbol that is defined in syscfg.h which is autogenerated by newt tool and contains all the settings set at package/app/target level.

Q: What if I need to set 2 constants? What’s the syntax?

A: You can set each setting in separate commands or separate key=value pairs with colon:

newt target amend <target> syscfg=FOO=1:BAR=2

Q: How do you know the constant is BLE_MAX_CONNECTIONS and not MYNEWT_VAL_BLE_MAX_CONNECTIONS? Is there a place I can see those names?

A: This is actually one of NimBLE’s settings - you can find these settings available for different packages in the syscfg.yml files in the repository. You can also use newt target config show <target> to show all settings with their current values, and then change any of these settings accordingly. Each setting will get a symbol prefixed by MYNEWT_VAL_ in the autogenerated syscfg.h file so you can get the actual setting name from this symbol. For more info on System Configuration and Initialization, please visit the Compile-Time Configuration and Initialization page in the OS User Guide.

Disconnect/Crash While Writing Analog Value From Central Module

Q: I’m trying to write analog sensor data from my central module to my peripheral module. I can receive the values from the ADC callback perfectly, but I’m not able to write them to the peripheral module. The peripheral module disconnects right when the ble_gattc_write_flat command is called. What could be causing the issue?

A: First, check the reason for the disconnect. The gap event callback should indicate the reason in disconnect.reason. If the code never reaches the disconnect callback, then the code most likely crashed. If so, check whether ble_gattc_write_flat is called from an interrupt context. Calling into the BLE host from within an interrupt is a bad idea in general, and may cause a crash to occur because the Bluetooth host attempts to log to the console during the write procedure. Logging to the console uses quite a bit of stack space, so it is likely that the interrupt stack is overflowing.

Instead, you should send an event to the event queue and handle this in a task context. You’ll need to associate the characteristic data with the event so that your event callback knows what payload to pass to the ble_gattc_write_flat() function. If you don’t need to perform multiple writes in rapid succession, then you can just use a single global event and single global buffer. However, you will still need to make sure your buffer doesn’t become corrupted by a subsequent ADC interrupt while you are in mid-write.

Documentation for ble_gap_disc_params

Q: Is there documentation somewhere on correct values for ble_gap_disc_params? I’m trying to do a passive discovery and getting BLE_HS_EINVAL.

A: Unfortunately, not at the moment. Here is a brief description of the fields:

  • itvl: This is defined as the time interval from when the Controller started its last LE scan until it begins the subsequent LE scan. (units=0.625 msec)

  • window: The duration of the LE scan. LE_Scan_Window shall be less than or equal to LE_Scan_Interval (units=0.625 msec)

  • filter_policy: The only useful documentation is the table in the Bluetooth spec (section 2.E.7.8.10). This field controls which types of devices to listen for.

  • limited: If set, only discover devices in limited discoverable mode.

  • passive: If set, don’t send scan requests to advertisers (i.e., don’t request additional advertising data).

  • filter_duplicates: If set, the controller ignores all but the first advertisement from each device.

Multicast Messaging and Group Messaging

Q: Is it possible to send a broadcast message by one of the devices present in the mesh (e.g. broadcast an event which happened)? Something like a push notification instead of continuously polling for it by a client.

A: It is possible to do so with a publish model. Group address or virtual address should help here, according to the Mesh spec. There is no real documentation on it but you can try it out on our btmesh_shell app. There is a shell.c file which exposes configuration client which you can use for testing (e.g. you can subscribe to virtual addresses). You can also trigger sending messages to devices. By playing with the dst command, you probably should be able to set destination to some group. However, since we do not support the provisioner role, there is a command provision which sets fixed keys so you can create a mesh network out of a couple of nodes without the actual provisioner.

Read the Value of a Characteristic of a Peripheral Device from a Central Device

Q: I want to read the value of a characteristic of a peripheral device from a central device which runs on Mynewt OS. How can I obtain the value using the following function?

int ble_gattc_read(uint16_t conn_handle, uint16_t attr_handle,
           ble_gatt_attr_fn *cb, void *cb_arg);

A: To see an example of this function being used, take a look at the blecent sample app. The data is in attr->om, which is an mbuf struct. There are dedicated APIs to access data in mbufs (see os_mbuf.h). attr->om->om_data is a raw pointer to access data in mbuf so you could also use it, but keep in mind that data in mbuf can be fragmented so you may not be able to access them easily like this. Thus, it is safer to use mbuf APIs instead. os_mbuf_copydata should be especially useful here since it can copy data from mbuf to flat buffer.