Timing question - possible to get an uninterrupted window?


#1

I know we can’t/shouldn’t block Bluetooth communication and that there’s a way to track the radio status via:

BLE.registerNotifications(radioCallbackHandler);

But is it possible to force the communication and have it reset the timer so I can get a guaranteed section of time where my code won’t be interrupted? For example if my timing sensitive code took longer than one period I could do something like:

BLE.sync()
//timing sensitive code
BLE.sync()
//remainder of timing sensitive code

Also how often does this interruption happen and how long does it last when there’s no incoming/outgoing data? I tried to time it via the notification callback and it appears to be roughly every 30ms with the radio on for about 1.4-1.7ms. I did this measurement in software via micros() so that likely impacts the accuracy of my results. I thought I read in another thread that the system interrupt was every 100ms; I doubt my measurement is off by that much.


#2

Great question. Unfortunately, the answer is that you can’t really block the radio interrupts. I mean, you can, but it is not going to lead to good things.

There are a few posts about this on the Nordic forums, their team basically always responds with simply “Don’t do it”. If you do, unpredictable issues can happen with the radio and you will almost certainly drop the connection.

The way BLE works is by sending data every connection interval. The connection interval is determined between the central and peripheral when the connection is established, then at every interval the two radios sync up (and transmit data if any is available). The connection interval will vary slightly based on the central, but it can be somewhere between 7.5mSec and 40mSec. Using the BLE gateway, it should be 20-30mSec, so your calculation sounds just about right actually.

There is one way to possibly improve the situation, and that is to increase the connection interval. The longer the interval, the less the radio interrupts your app. We have already added this to the develop branch of the firmware, and I am setting a goal to get this released in the next 2 weeks. So you will be able to set this value to up to 300mSec, meaning you will get a lot more time between radio events to do what you need.

The other option, if this would work, is to turn off BLE and do what you need and only reconnect when you have to. So you can disconnect, turn off advertising, run your code, then turn advertising back on and reconnect.

What timing are you doing? How long of a window do you need?


#3

So you can’t force an early connection because both sides agreed in advance when the next one is?

I’m primarily asking to better understand the options and how things work; I’m having a bit of fun working around this. Secondarily I’m wondering how to improve the reading of temp sensors without have to resort to a brute force method of trying it a few times until it works.

If you can’t force a fresh window my backup idea is to track the micros() since the last time the radio turned off and within the loop only run timing sensitive code if it had just happened. It’s unclear if this would end up being more efficient than the brute force method as it may cancel out the benefits due to looping while I wait for a window. I plan to try it anyway :wink:

For the DS18B20 it looks like the timing sensitive sections are 10ms long but there is a large delay between the two of them. So for this to work I’d need to split the operations so the main loop can pick a good block of time to start the process and then after a period time (100ms-800ms depending on precision) another block of time to read the result. Theoretically it seems that would allow for a perfect read every time.

I don’t like the idea of turning off the radio completely as I assume it would take several seconds to reconnect and I’d eventually like this to run off a battery. If I’m wrong and this could be a power efficient option then I’ll give it a try as well.


#4

Correct, the peripheral (DK) and central (gateway) negotiate the connection interval ahead of time. Theoretically they can renegotiate during the connection, so it could change, but it can’t be done on the fly only one time.

Depending on your use case, turning off the radio could be very battery efficient. For example, if you only needed to read the temperature every 5 minutes and publish it, shutting off the radio may make sense. If you need to send it much more frequently, then it may not. The radio is the biggest power draw on the device, so turning it off when not needed can be a big advantage. Of course, as you pointed out, there is time/power required to reconnect so it may not be efficient if you have to turn it on/off frequently. It depends on what you are trying to do really.


#5

That’s a good point and is actually what I plan to do long term. Plus it’d make for a good control experiment. If I still had issues while the radio was disabled then I’d know it that wasn’t the cause.


#6

I have no issues reading the sensor when the radio is disabled. When I leave the radio on but implement a check to only start reading the sensor within a few milliseconds of the last connection my success rises from 69% to 74%. Likely because only the first part of the read can happen within the window. When I shift this check into the dallas library and have it wait at the beginning of both timing sensitive parts then success rises to 99%. Perhaps I’m missing one other timing sensitive section.

What’s the correct way to turn off the radio? I figure I need to disconnect and then stopAdvertising but without a delay between them it does an SOS of 1 or 2 blinks which isn’t listed as a valid code.

if (BLE.getState() == BLE_CONNECTED) {
    BLE.disconnect();
    delay(100);
}
if (BLE.getState() != BLE_OFF)
{
    BLE.stopAdvertising();
}

I tried various delay values and 100ms was the lowest that didn’t reliably cause an SOS. I could understand 30ms or whatever the connection interval is but 100ms seems odd.


#7

This may be a little tricky for now, the disconnect command returns after the disconnect is started but not completed. I will open an issue on this and test before the next release.


#8

Looks like the cause is trying to disconnect a 2nd time. A simple solution would be to add another BLE state, ie Disconnecting, and set that before returning. That way it’d be easy to prevent/ignore a 2nd disconnect call when already in progress. When I updated my code to only call it once I no longer got an SOS. So in the mean time I added my own disconnecting flag which I set to true upon calling disconnect and change to false when the BLE state changes.

Looks like stopAdvertising is ignored if called before disconnect and/or not in a BLE state of Advertising. Is there a reason for that? Seems a bit odd to disconnect, wait for it to start advertising and then tell it to stop. So the state changes from 3 (connected) to 1 (advertising) with disconnect and then 1 (advertising) to 0 (off) with stopAdvertising. If only disconnect is called or stopAdvertising is called before disconnect then it changes from 3 to 1 and back to 3.


#9

All good points, I will open up an issue on this and we can try to clarify this better moving forward.


#10

Issue is located here: https://github.com/bluzDK/bluzDK-firmware/issues/33

If you would like to add anything else, please feel free.


#11

Eric, is is possible to disconnect briefly without losing the particle connection? In my testing on the latest beta I can sometimes disconnect/stopAdvertisting and reconnect about a second later and still have the particle connection, assuming ‘Particle.connected()’ is accurate. Most times though I do lose the connection and on average it takes 15sec to reconnect but I have seen times when it’s been longer than 60sec.

Also I’ve noticed that Particle.connected() can be true while BLE.getState() can be in a state other than Connected. That was causing me some trouble so I started checking for both; ie if (BLE.getState() == BLE_CONNECTED && Particle.connected())

Basically I’m looking at 2 use cases. The first is a to go offline very briefly to get do an operation without having the radio interrupt. The second is to stay offline and only come online for brief periods of time to report data and allow for an OTA update.


#12

For the first question, the answer is basically no. While this could be technically possible, the gateways currently are designed to close the socket to the Particle cloud when the BLE link disconnects. There could be ways to do this, so the gateway could be changed to keep the socket open even if BLE disconnects, but it would be hard to sync things back up when it reconnects. Plus, there are timing and other issues involved. So we didn’t really support this case.

For the second, you can certainly use the current commands to disconnect from BLE and stop advertising. This will effectively allow you to disconnect from the Particle cloud when you need to. Is the point to save battery? As you pointed out, it can sometimes take a while to reconnect so this would need to be “worth it”. If you were only reconnecting every hour for a minute, it would save battery. But if you were constantly reconnecting every minute, it wouldn’t be as the price to connect would outweigh the savings of disconnecting.


#13

Thanks. That’s exactly what I’m trying to figure out. To get a rough sense of when it makes sense to stay offline considering the time it takes to reconnect. I think I may need to go offline at least once to properly iterate through multiple one wire devices. Things get complicated when I can’t simply retry the prior command when I don’t get the expected result. Once I’ve iterated and have the device addresses then I can rely on retries to get a good result.

The time-frame I’m looking at is popping online every 5-15min. Do you think that would be worth the 10-90sec re-connection cycle from a power perspective? I can run tests to get time based averages but I don’t have an easy way to monitor power use. Last I checked the docs said not to invoke deep sleep until the connection is established so likely several distinct power states to consider.


#14

Sorry for the delay. I would guess that 5 minutes is on the low side of power savings, that may not be long enough to really gain much. 15 minutes may be more beneficial. However, this is just me guessing, taking some measurements would be the only accurate way to tell where that line really is.

You can also look at other ways to reduce power on the BLE link. A quick and cheap way is to turn down the transmit power of bluz. Also, we do expose the connection interval parameters now on the gateway, though at the moment they need to be set using Particle function calls. This can allow you to set the interval to up to 300mSec, which is more then 10x larger then the current default value. This means the radio will be used 10x less, greatly increasing battery performance.

Factors like connection interval can also affect how long you stay offline for as well. If you use a longer connection interval, then you would need to stay offline longer to get the same savings.