Hi,
We are using SDK 5.0.4 and I was looking at the user_sleepmode example.
It looks like the program listens to button-click interrupts in two cases.
The first case is during a connection. To begin listening,user_app_set_button_event
is called and executes:
wkupct_register_callback(user_app_button_press_cb);
wkupct_enable_irq(WKUPCT_PIN_SELECT(GPIO_BUTTON_PORT, GPIO_BUTTON_PIN),
WKUPCT_PIN_POLARITY(GPIO_BUTTON_PORT, GPIO_BUTTON_PIN, next_event), // polarity
1, // 1 event
10);
and the listening is stopped byuser_app_disable_button
which callswkupct_disable_irq();
.
The listening callback (user_app_button_press_cb
) also callsuser_app_set_button_event
to keep listening to button clicks (actually it listens to switches in the button-mode, by choosing the right "next_event").
The second case is when the program stops advertising (after 10 seconds). Whenuser_app_adv_undirect_complete
调用的状态为GAP_ERR_CANCELED
(i.e. it's a deliberate adv-stop) it calls:
arch_ble_ext_wakeup_on();
// Configure wakeup button
app_button_enable();
The purpose ofarch_ble_ext_wakeup_on
is:"Puts the BLE core to permanent sleep. Only an external event can wake it up.". It simply sets an internal flag to true.
Then,app_button_enable
calls:
app_easy_wakeup_set(app_wakeup_cb);
wkupct_register_callback(app_button_press_cb);
wkupct_enable_irq(WKUPCT_PIN_SELECT(GPIO_BUTTON_PORT, GPIO_BUTTON_PIN), // select pin (GPIO_BUTTON_PORT, GPIO_BUTTON_PIN)
WKUPCT_PIN_POLARITY(GPIO_BUTTON_PORT, GPIO_BUTTON_PIN, WKUPCT_PIN_POLARITY_LOW), // polarity low
1, // 1 event
40);
i.e. it savesapp_wakeup_cb
aside to be called in the future byapp_easy_wakeup
,并运行与第一种情况类似的代码,以便开始侦听按钮中断。
When the interrupt occurs,app_button_press_cb
is called and executes:
if (GetBits16(SYS_STAT_REG, PER_IS_DOWN))
{
periph_init();
}
...
If I understand correctly, this code must be called in external wakeup during deep-sleep (Is it harmful to call it when using extended sleep?).
Then, the app_button_press_cb continues by calling:
if (arch_ble_ext_wakeup_get())
{
arch_set_sleep_mode(app_default_sleep_mode);
arch_ble_force_wakeup();
arch_ble_ext_wakeup_off();
app_easy_wakeup();
}
i.e. it checks that the external-wakeup-flag is on, initializes the sleep-mode (app_default_sleep_mode is deep-sleep), wakes up the BLE, turn off the external-wakeup flag (i.e. timers and BLE events can now wake up too) and callsapp_easy_wakeup()
(which callsapp_wakeup_cb
as I explained before).
What are the advantages of the mechanism in the second case? We could avoid callingarch_ble_ext_wakeup_on()
and then we won't have to re-configure the sleep mode and re-wake the BLE. What's the point of callingarch_ble_ext_wakeup_on()
if the program doesn't have any timers and doesn't advertise (i.e. timers and BLE events cannot wake up the programanyways- so only an external-wakeup can).
Will the program consume less power during deep-sleep if we usearch_ble_ext_wakeup_on
?
How comes the second case never callswkupct_disable_irq()
? Does going to sleep afterarch_ble_ext_wakeup_on
means that you don't have to callwkupct_disable_irq()
after you wake up?
Thanks,
Oren Zomer
Hello Oren,
I apologize for the delay in answering your questions...
Hi LC,
Thank you for the informative response.
我们现在注意到CFG\u MAX\u SLEEP\u DURATION\u EXTERNAL\u WAKEUP\u MS参数-
rwip_sleep()
function is very complicated, but we understand you explanation.We want the module to stay in deep sleep as long as possible and not wake up every 10 seconds. We don't care about polling the UART - in our use-case, once the module is burned, it will never be connected to a UART.
Is it possible to increase the CFG_MAX_SLEEP_DURATION_EXTERNAL_WAKEUP_MS parameter? If so, what is the maximal value?
I suppose we should use
arch_ble_ext_wakeup_on
when we want to deep-sleep until external wakeup. However, in some cases we just want to deep-sleep for long periods of time (hours, days) - we do it by creating a periodic-timer ofKE_TIMER_DELAY_MAX-1
and a counter. We are OK with waking up every 300 seconds, but don't want to wake up every 10 seconds...当做,
Oren Zomer
P.S.
We don't care much about imprecise timings - if we set a timer for 1 hour we don't care if it will wake up after 50 minutes or 70 minutes. 20% accuracy is good enough for our use-case.
Hello Oren,
Yes, you can modify the value ofCFG_MAX_SLEEP_DURATION_EXTERNAL_WAKEUP_MSfrom 1sec upto a maximum of 23.3Hrs (value to be assinged in seconds). When thearch_ble_ext_wakeup_on调用它会抑制呢value to put the BLE into permanent sleep which is the same for any value on the sleep duration. However, if thearch_ble_ext_wakeup_offis invoked then the value on sleep_duration will come into effect.
For your second requirement, I haven't fully understood the use case. Can you elaborate the scenario.
However, you can extend the sleep duration by changing the above mentioned define. which will control the wakeup period for the BLE. However, this can be supressed by invoking thearch_ble_ext_wake_on()to wake up on an external event (Or) you can also use a timer as a wakeup mechanism instead of an external event.
Note: The sleep process for BLE events (assuming 10s) is managed by an intelligent algorithm that will decide to put the BLE to sleep or not. When we wakeup the BLE at some random time, this algorithm will check to see if it is efficient to go back to sleep or stay awake for the next normal event (say advertising) and based on the decision, this may consume more energy than we expect. Please consider this when scheduling the wakeup
当做,
LC
Hello LC,
The second requirement is, for example, when we have a sensor (button) and we want to deep-sleep until an external event happens or until 1-hour passed (since we began sleeping).
We must not call
arch_ble_ext_wakeup_on
in this case because we need to have a timer to wake up after 1-hour if no external event happens...app_easy_timer
should not be called with values aboveKE_TIMER_DELAY_MAX-1
(5 minutes) so we use a timer ofKE_TIMER_DELAY_MAX-1
and a countdown counter that is initialized to 12.When the timer-callback is called we reduce the counter by 1 and then:
- If the counter is above 0 we recreate the timer (with a delay of
KE_TIMER_DELAY_MAX-1
, i.e. 5 minutes).- If the counter is 0, we know that 12*5min = 1hour has passed.
If an external event happened in between, we cancel the timer.
I actually think this trick should be a built-in feature in
app_easy_timer
in case large delays are used (in v5.0.4 the implementation ofapp_easy_timer
callsASSERT_ERROR(delay < KE_TIMER_DELAY_MAX)
, i.e. large delays are simply not allowed).Do you know if the default 10-seconds wakeup (due to
CFG_MAX_SLEEP_DURATION_EXTERNAL_WAKEUP_MS
) also happened in previous SDK versions? To be specific, I want to know about versions 3.0.4 and 3.0.8. We will increase the value to 23.3 hours, but we already have lots of modules that were already burned with previous SDKs.当做,
Oren Zomer
Hi LC,
23小时是82800000毫秒。
MAX_SLEEP_DURATION_EXTERNAL_WAKEUP
is defined to beMS_TO_SLOTS_CONVERT(CFG_MAX_SLEEP_DURATION_EXTERNAL_WAKEUP_MS)
and theMS_TO_SLOTS_CONVERT(x)
macro gives((int)((1000 * x) / 625))
.The multiplication by 1000 creates a compilation warning: "integer operation result is out of range" warning (although the final value, after dividing by 625, is in the range).
A quick fix could be to change the macro to:
((int)((1000 *(很久)x) / 625))
.Just wanted to let you know...
当做,
Oren Zomer
Hello Oren,
As of now, what we would suggest is use a timer and restart the time until you reach your desired time. As that would be the best way which also helps in your debugging.
注意:我们不建议更改MAX_SLEEP_DURATION_EXTERNAL_WAKEUPas it is effectively changing the SDK implementation. It is also the same in the previous version 3.0.4 and 3.0.8.
We would consider your suggestion for making it a default option in theapp_easy_timer.But, as of now it is not available as a default feature.
Also, thank you for the suggestion to change the macro. I will check it out and escalate to make the correction.
当做,
Leepeng