Background
I am attempting to build a system in which a Nordic NRF52840 SoC, is connected to a mobile app (iOS / Android) via BLE and both devices play back audio-visual feedback in a synchronized manner. Both devices are able to take care of their own playback so not much data needs to be exchanged while playing.
What I am having trouble with is to synchronize the SoC's timestamp with the app reliably, so that the start of the playback can happen at exactly the same time.
Setup
- Mobile device is master and SoC is the peripheral
- Mobile and SoC are connected and bonded
- Multiple SoCs could be connected to the mobile device and the system should still work reliably
- The connection interval is set to 30ms
- Packet transmission from the SoC to the master is done through Notifications
- Looking at the arrival timestamps on the master by using Android's Bluetooth HCI Snoop Log with Wireshark and logging the values on XCode for iOS
Goals
- 5ms synchronization accuracy
- Measured by looking at how the offset between the SoC's and master's timestamps changes across multiple synchronizations (* Figure 1)
Approach
- There is a radio notification interrupt set up on the SoC, that triggers 5500µs before connection events
- At that point, I store the current timestamp +5500µs (the timestamp at the time of the assumed packet transmission)
- As enqueueing BT packets on the software interrupt is a bad idea, the main loop calls sd_ble_gatts_hvx() on its next iteration to send the previously calculated timestamp
- Master keeps track of the SoC's timestamp individually by calculating an offset with its own timestamp (native monotonic clock)
- I send the timestamp from the SoC to the master multiple times, calculating the difference between their clocks' timestamp offsets to see if they are always the same, as they should be, since the clocks run independently in parallel
* Figure 1: Expected timestamp offset across synchronizations
Questions
- Due to the nature of BLE, there seems to be no way to guarantee that the timestamp sync packet is sent out with the next connection event
- It is assumed that there are enough resources to enqueue the packet, when there is a NRF_SUCCESS return code produced by sd_ble_gatts_hvx()
- Q1: Is this assumption correct?
- I've seen a random difference between the timestamp offsets for one device, which is sometimes within 20ms and sometimes seems to be multiples of the connection interval (up to 4 times 30ms)
- Q2: What could be the cause of the smaller errors? I think that maybe the transmission window is the culprit here
- Please note that the packages are being received with some milliseconds of difference between them, according to the data in the HCI Snoop Log (* Figure 2)
- Q3: How could it be that some packages are being received a couple of connection events after I enqueued them if there seems to be enough space in the queue and I did not enqueue other packets?
- Q2: What could be the cause of the smaller errors? I think that maybe the transmission window is the culprit here
- As part of the tests, I've enqueued more than 6 packets multiple times and the way that the errors are reported on the SoC is not always consistent when using the same device as master i.e. sometimes I can only enqueue 4 or up to 7 packages with a result of NRF_SUCCESS
- Q4: What's the reason for this behavior?
- Since I only need to synchronize the timestamps once per connection, I could do this by placing the timestamp in the SoC's advertisement data, as mentioned in this other entry in the forum
- Q5: Do you recommend this approach, is it faster or more reliable than the regular notifications or indication?
- Q6: Are there other alternatives to tackle this?
- Q5: Do you recommend this approach, is it faster or more reliable than the regular notifications or indication?
- On the same note as point no. 4: I've seen that iOS keeps this advertisement data cached and it can be rather unreliable for me to have the updated version on the master
- On top of that, as I rely on the ANCS for notifying push notifications to the peripheral, iOS would automatically connect to the SoC, without me being able to grab the advertisement data beforehand
- Q7: Would it be possible for the SoC to advertise the data even after it has established a bonded connection to the master?
- When looking at the current approach:
- Q8: Is this a reasonable approach? What kind of accuracy can be expected?
- Q9: What about delays on phone side, is there anything in particular that I should take special care of?
- Q10: Are there any further resources on the topic of timestamp synchronization that you would recommend?
* Figure 2: Timestamp difference between received notifications as logged on Android OS