I have a BLE peripheral device (for which I control the firmware) and two mobile apps acting as centrals, one on Android, the other on iOS 8.1.
The Android app works fine. The iOS does not. It will spontaneously disconnect some time after connection. The error is:
Code=6 "The connection has timed out unexpectedly."
The time between connection and this disconnection is random. I've measured from 40s to 4m30s.
All the peripheral device is doing with the BLE connection is writing some firmware logging messages to the mobile app UI. Just a few writes to that one characteristic in quick succession every few minutes. There is no error in the peripheral device firmware.
How do I find the cause of the disconnection?
After some extensive support from Nordic Semiconductor, the manufacturer of the BLE module on the peripheral, we're pretty sure the cause of this is an inaccurate clock on the iPhone 5C BLE module. That is, it's less accurate than stated in the connection request. Here's my question on the Nordic forums:
https://devzone.nordicsemi.com/question/51258/ios-8-disconnection-code6-the-connection-has-timed-out-unexpectedly/
So I was facing this problem with Microchip BM78 Bluetooth module talking with iOS. I found this tech note which was very helpful:
https://developer.apple.com/library/archive/qa/qa1931/_index.html
These settings are flashed onto the BM78 module. Here are the Apple 'rules' from the above tech note:
Interval Min ≥ 15 ms (multiples of 15 ms)
Interval Min + 15 ms ≤ Interval Max (Interval Max == 15 ms is allowed)
Interval Max * (Slave Latency + 1) ≤ 2 seconds
Interval Max * (Slave Latency + 1) * 3 < connSupervisionTimeout
Slave Latency ≤ 30
2 seconds ≤ connSupervisionTimeout ≤ 6 seconds
My values (working well):
Interval Min = 15ms
Interval Max = 30ms
Slave Latency = 4
Connection Supervision Timeout =~ 5 seconds
The same issue happened to me when I developed Bluetooth on iOS14. I adjusted the roles mentioned by Jim Holland at first, but the issue still occurred. Then I doubted it because of the low RSSI of the signal. After moving the test phone closer to the device, the issue disappeared! After some tests, I found this issue occasionally shows when RSSI is lower than -90.
Related
We are developing a device which communicates with our iOS/watchOS apps via Bluetooth LE and has to stream a lot of sensor data for an extended time period (hours). Everything works fine under iOS 15.x, but we've found out that iOS 16 betas (and the RC) changed something in the negotiation process: previously we've used 15 ms Connection Interval, but iOS 16 (and watchOS 8) most of the time negotiates 24 ms, which is too wide for our bandwidth. The long connection interval causes packet loss (9-33%), and after 3 failed retries (3x30 sec) our hardware drops the connection.
I've checked all forums and documentation available but didn't found any indication that something changed. Is there any new parameters we can look into to fix this issue?
EDIT: Changed 30 ms to 24
You've probably set both Interval Min and Interval Max at 15ms. Apple explicitly says that this may caused devices to negotiate to 30ms (see section 41.6 Connection Parameters):
If an accessory requests both an Interval Min and Interval Max of 15 ms, some devices will scale the interval to 30 ms to balance power and performance constraints.
Basically, asking for "as fast as possible, no margin" translates into "yeah, everyone asks for that, how about moderately fast?"
However, you may ask for a faster CI if you include HID:
If Bluetooth Low Energy HID is one of the connected services of an accessory, a connection interval down to 11.25 ms may be accepted by the device.
Though I believe what iOS 16 is doing exactly matches Apple's spec (they always said that 15ms could be negotiated to 30ms), you should still open a Feedback+DTS to discuss the impact on your product and use case. Sometimes these things are by accident, and sometimes they're experiments that get rolled back.
We had the same issue with our product. We used a 7.5-15ms interval that was accepted by iOS15 & below, though it didn't meet the Apple Design Parameters (we thought we could get away with it since it was working). We had to change it to 15-30ms for the issue to be resolved, though now the amount of time it takes to transfer data for Androids has doubled.
As Rob mentions in this thread, it seems that for iOS16.0, Apple decided to strictly follow their guidelines and not allow anything outside those "set" requirements, even though they allowed it in the past. However, it seems that Apple has reverted back to how iOS15 was operating with iOS16.1. (There is no documentation that says this though - just know through testing)
If you need a quick fix right now, if you have users, have them update to iOS16.1. Your device should operate as it should when it used to run on iOS15.
For a long term solution, I would follow Rob's suggestion.
I am looking at speeding up the connection time between my iOS application and the peripheral.
I have looked up Apples Documentation on the subject: https://developer.apple.com/library/content/qa/qa1931/_index.html
Originally (prior to reading the doc above) I had the advertising interval set to 2 seconds to, what I had thought would be, a good compromise between power consumption and connection time. Having read the documentation further I have changed the interval to 1285 ms.
#define ADVERTISING_INTERVAL 2056 ble_obj.setAdvertisingInterval(ADVERTISING_INTERVAL);
The device is always discovered quickly by the app but the problem comes when trying to connect.
However, I have seen no increase in speed in connection time between my application and the peripheral device. Connections between the devices can take anything from 3-4 seconds up to 30+ seconds.
Is there something I am missing? Either on the peripheral or the central side?
Peripheral BT chip is the Nordic Semiconductor NRF51822.
On examining the devices advertisement packet on the Nordic Semiconductor app I can see that the advertisement interval normally varies from 1275 ms to about 1295 ms (as expected? due to the random time added to the advertisement packet)
NOTE
Have also tried with an advertising interval of 152.5 ms and am still not seeing any major improvement in connection speed. I am , obviously, seeing a marked improvement in speed of discovery
What you observe is normal. Don't expect fast connection setup with an advertising interval of more than a second.
Core Bluetooth uses a high duty scan window/interval for the initiation the first seconds. If it doesn't connect then it continues to scan with much more power restrictive parameters.
After spending hours around the web, I cannot find any documentation about the background BLE scanning rules used by IOS.
As it is not possible to set the scan window on IOS, I am looking for the rules defined by Apple when IOS is scanning in background.
Context
I am working on a wearable peripheral which can be disconnected sometimes when it is out of reach with the phone. The goal is to reconnect quickly (less than 5s) when the peripheral is close enough to the phone. The peripheral has battery constraints so I cannot advertise every 20ms forever, so I am looking for a clever way to reconnect my peripheral to the phone.
If I know how the background scanning mode is working, I would be able to define a smart advertising interval in order to save battery.
Use case
If my peripheral advertises every 1285ms, how long does it will take to be discovered by my IOS application in background mode for 10 minutes?
Not sure exactly what your question is.
I suppose you have read Apple's "Bluetooth Accessory Design Guidelines for Apple Products"?
https://developer.apple.com/hardwaredrivers/BluetoothDesignGuidelines.pdf
In it, they state:
3.5 Advertising Interval
The advertising interval of the accessory should be carefully
considered, because it affects the time to discovery and connect
performance. For a battery-powered accessory, its battery resources
should also be considered.
To be discovered by the Apple product, the accessory should first use
the recommended advertising interval of 20 ms for at least 30 seconds.
If it is not discovered within the initial 30 seconds, Apple
recommends using one of the following longer intervals to increase
chances of discovery by the Apple product:
152.5 ms
211.25 ms
318.75 ms
417.5 ms
546.25 ms
760 ms
852.5 ms
1022.5 ms
1285 ms
Note: Longer advertising intervals usually result in longer discovery and connect times.
Upon discovering the BLE device, iOS will notify apps that are looking for it (based on the advertised service UUID), which will then be able to connect to it.
Apple recommend a 100 ms interval for iBeacons.
This (pretty old, from 2012) discussion states that:
the median discovery time when the phone is in standby is about 60
times the advertising interval. The 95-percentile discovery time when
the phone is in standby mode is about 300 times the advertising
interval
This (slightly more recent, but from Dec 2013) answer states that:
While scanning in the foreground will likely immediately discover a
device advertising next to it, discovery in the background can take up
to ~60 times longer.
There's a problem when (average) advertising interval is near to an integer multiple of the scan interval, then chances are that discovery-time can rise infinitely (, i.e. scanner will never see the advertising, as ADV always occurs outside the scan window).
Probably the ADV-interval list from Apple's design guideline shows optimum values, but it does not tell how to determine discovery-times. That's a mess!
I'd even go further and say: If the Smartphone (Apple or any other) manufacturer does not exactly specify the scan parameters (interval, window, and eventually filter settings) for each power mode, then you're lost and cannot correctly estimate discovery performance.
I know the default connection interval for CoreBluetooth is 30 ms. I've read couple of articles that claim they can reduce it 30 ms > by changing the min and max of the interval. I didn't see any explanation of how they were changing the parameters of it? I am assuming this is all in the iOS end.
Currently I am working on a project where the iOS device is sending packets to the bluetooth le device. When I was writing without response, there were a lot of packets being dropped so I added a handshake so once the bluetooth device receives a packet the iOS sends the next packet. This is currently taking a long time to upload a file since the connection interval is 30 ms which I am trying to reduce.
Any suggestions would be helpful
td;lr How do I change the connection interval on iOS
Solution So after doing research there is no public API that allows iOS devices to request for a connection interval change request. For Android this is possible.
There is no API on iOS for a app as master (using CBCentralManager) to modify the initial Connection Parameters when connecting to a peripheral.
However, the slave can suggest new connection parameters using a L2CAP Connection Parameter Update Request (see Bluetooth 4.0 specification, Volume 3, Part A, Section 4.20), which iOS will accept if they are reasonable (see Bluetooth Accessory Design Guidelines for Apple Products section 3.6 “Connection Parameters”). Peripherals should do this because different operating systems have different default connection parameters that might not be optimal for a particular peripheral. For example, if you rare implementing your peripheral in iOS or OSX, call -[CBPeripheralManager setDesiredConnectionLatency:forCentral:. Or, if you are using the TI BLE stack to program a CC2540 or the like, call the function L2CAP_ConnParamUpdateReq.
We are developing a BLE sensor Peripheral to work with an iPad, that requires the following throughput of data on the BLE notification characteristic (no acknowledge) using a TI CC2541 BLE module and a custom profile:
One 20 bytes (GATT maximum standard packet) every 10ms, or since we appear to have a limit of 4 packets per connection interval, this equates to one connection interval every 40ms. Throughput required is 2,000 bytes per second, the TI website recommends the CC2541 BLE solution be used for several sensor devices requiring this level of data throughput.
The profile for the BLE module is set with min and max connection intervals of 20ms and 40ms respectively, which should suffice. The "Bluetooth Accessory Design Guidelines for Apple Products" document suggests that the minimum and maximum connection intervals we set, as above are correct. We are using the latest iPad and Apple tools for iOS 6 on a new Mac Mini / Mac Book.
With a simple test program on the iPad, we can get the link to work well sending 20 byte packets to the BLE Peripheral at intervals of 20ms, however once we lower this to 10ms as required we start loosing packets or getting corrupt packets, we have the FIFO empty interrupt turned off so we can handle the sending to the BLE module FIFO quicker, and we are using the maximum Baud rate of 230400 to send the 20 byte packets to the BLE TX FIFO from the micro.
We realise we are at the top end of the BLE transfer limit, and of what is possible. Can anyone advise if there is a solution to achieving 2000 bytes per second throughput using the TI CC2541 BLE chip / module with an up to date iPad?
We use TI 2540 (BLE stack version 1.3.2) succesfully with iPad/iPod/iPhone (iOS 6.x and 7.x). We currently send 75 notifications of 20 bytes per second => 1500 bytes/second. But I have tried to send 125 notifications and that worked as well.
Of course the more you send the greater likelihood of loosing data, e.g., less time to resend a NACK'ed message.
I have experienced that iOS' BLE stack may enter a mode where it begins to NACK messages continuously. If this happens you will loose a lot of messages. I have reported an error to Apple about this. (This problem seems to have been fixed in iOS 7.1.beta3/4.)
I currently have:
// Minimum connection interval (units of 1.25ms, 80=100ms) if automatic parameter update request is enabled
#define DEFAULT_DESIRED_MIN_CONN_INTERVAL 10
// Maximum connection interval (units of 1.25ms, 800=1000ms) if automatic parameter update request is enabled
#define DEFAULT_DESIRED_MAX_CONN_INTERVAL 20
Yes, it doesn't conform with Apple's guidelines. But I believe they can be relaxed in our case.
UPDATE: I have also tried to use an iDevice as peripheral, i.e., BTLE between two iDevices. Here I have sent 150 messages per second without any problems.
Are you sending "write without response" commands? You can send 4 packets per connection event this way. Using you previous 20ms connection interval, you would be sending 4 packets with 20 bytes every 0.02 seconds. Putting that together: 4*20/0.02 = 4000 bytes per second easy.
I highly doubt you are getting corrupt data. The link layer adds a CRC and a 2 bits of "next expected" to BLE packets to ensure A) all the bits are received correctly and b) packets were not sent out of order. The TI stack and iOS control the link layer so I doubt you've botched that.
Here are few observation on throughput that we found during our RnD on iPhone with BLE. The below data is based on write with response.
iPhone 8 (BLE 5.0) as Central and Linux desktop (Ubuntu 16.04 with BLE dongle 4.0): MTU = 2048 : Throughput - 2.5 KiloBytes per sec.
iPhone 8 (BLE 5.0) as Central and Android OS with BLE version 4.2 as Peripheral(Xiomi Mi A1): MTU = 180 : Throughput - 2.5 KiloBytes per sec.
iPhone 8 (BLE 5.0) as Central and iPhone 7 plus (BLE 4.2) as Peripheral : MTU = 512 : Throughput - 7.1 KiloBytes per sec.
iPhone 8 (BLE 5.0) as Central and Samsung S8 (BLE 5.0) as Peripheral : Samsung S8 failed to work as peripheral
iPhone 8 (BLE 5.0) as Central and iPhone 8 plus (BLE 5.0) as Peripheral : MTU = 512 : Throughput - 15.5 KiloBytes per sec.
As you can see, as the MTU value increases, we get maximum throughput. But we cannot increase to any limit. The above MTU values are the default maximum allowed MTU value as per the given configuration. [MTU - Maximum Transmission Unit. i.e maximum bytes that can be sent in one write request]
Comments are welcome to the above data.
iOS 7 seems to have made some optimizations regarding the throughput levels for BLE transfers. Try it again on an iOS 7 device.
You don't really pose a question, but I can verify that your desired limit of 2000 bytes/sec is possible.
check out the selected answer on this forum post (http://e2e.ti.com/support/wireless_connectivity/f/538/p/353327/1244676.aspx#1244676) to see how we made it work.