How to use ke_timer during wakeup when BLE is down

How to use ke_timer during wakeup when BLE is down

The idea of ke_timer is the usage of ble timer, and convert ble timer interrupt to ke_message and send to corresponding task message queue.

ke_timer mechanism need main loop schedule, and main loop schedule need BLE is active.

In some application design, system will enter permanent sleep to waiting for external wakeup which will power down BLE.

After CPU wakeup, CPU will wakeup BLE through wake_ble_up(). This function will write certain register to issue ble wakeup req.

BLE will eventually active after a few interrupts, once ble timer is setup during this stage, system will get abnormal ble timer behavior.

Several customers met ke_timer didn’t work correctly after wake-up from sleep randomly, or some customers claimed its design work well only without enable sleep.
The phenomena is one certain timer(10s) will happen in random time-stamp, sometimes after 3s, 6s,8s, even 100ms, or not get executed.

We identify Dialog SDK/Reference design have one rule to follow to make sure ble_timer get correct programmed and timer message handler get correctly executed after wakeup.

In HID reference, we have below description to make sure ble timer work well after it start from IDLE_ST.
****************************************************************************************

@brief Handler of a dummy TASK_APP msg sent to trigger the adv timer

In case of advertising start from IDLE_ST, a dummy message is sent to the TASK_APP.

This msg is put in the queue when the BLE is woken up. When the handler is called,

it is certain that the BLE is running and the timer may start.
*
*

@return KE_MSG_CONSUMED
****************************************************************************************
*/
int app_start_adv_msg_handler(ke_msg_id_t const msgid”

In SDK 3.0.6 , we have the similar wakeup msg,
//Wakeup BLE here

#if (EXT_SLEEP_ENABLED)
app_set_extended_sleep();
#elif (DEEP_SLEEP_ENABLED)
app_set_deep_sleep();
#else
app_disable_sleep();
#endif
SetBits32(GP_CONTROL_REG, BLE_WAKEUP_REQ, 1);
app_ble_ext_wakeup_off();

ke_msg_send_basic(APP_WAKEUP_MSG, TASK_APP, NULL);

ke_timer should start only after APP_WAKEUP_MSG handle get executed.

We usually met this case because this scenario is easy to happen, below code run from wakeup call back will trigger this case:
start_adv_undirected(); // The message handle will be executed only after CPU run into main loop
app_timer_set(APP_HID_ADV_TIMER, TASK_APP, ADV_KEY_PRESS_TO); // That’s said, app_timer_set will run before any msg actually executed, this will actually program ble timer before ble is active.

Workaround

We have done the following extension of the app_setup_timer. It checks if the BLE is active and if not, it will automatically generate the message and setup the timer by itself.

This workaround also have one limitation to make sure no duplicate dummy APP_CREATE_NEW_TIMER have been send.

uint8_t app_check_BLE_active (void)

{

return ((GetBits16(CLK_RADIO_REG, BLE_ENABLE) == 1) &&\

(GetBits32(BLE_DEEPSLCNTL_REG, DEEP_SLEEP_STAT) == 0) &&\

!(rwip_prevent_sleep_get() & RW_WAKE_UP_ONGOING)) ;

}

int app_create_new_timer(ke_msg_id_t const msgid,

const struct create_new_timer_struct *param,

ke_task_id_t const dest_id,

ke_task_id_t const src_id)

{

ke_timer_set(param->timer_id, param->task_id, param->delay);

return (KE_MSG_CONSUMED);

}

/**

****************************************************************************************

* @brief Start a kernel timer

*

* @return void

****************************************************************************************

*/

空白app_timer_set (ke_msg_id_t const timer_id ke_task_id_t const task_id, uint16_t delay)

{

// Delay shall not be more than maximum allowed

if(delay > KE_TIMER_DELAY_MAX)

{

delay = KE_TIMER_DELAY_MAX;

}

// Delay should not be zero

else if(delay == 0)

{

delay = 1;

}

if (app_check_BLE_active())

ke_timer_set(timer_id, task_id, delay);

else

{

app_ble_force_wakeup(); //wake_up BLE

//send a message to wait for BLE to be woken up before executing the

struct create_new_timer_struct *req = KE_MSG_ALLOC(APP_CREATE_NEW_TIMER, TASK_APP, TASK_APP,

create_new_timer_struct);

req->delay=delay;

req->task_id=task_id;

req->timer_id=timer_id;

ke_msg_send(req);

}