RTC WAKEUP from Stop1 and BLE on WBA55cg
Hello guys.
On a WBA55CG running ThreadX with a custom BLE peripheral application, the device becomes permanently stuck after a random number of sleep/wake cycles (anywhere from ~10 to ~20+). The CPU stays alive, but the advertising timeout never fires again, so the application never returns to STOP 1 mode. Only a hard reset recovers it.
The device wakes from STOP 1 mode from either an interrupt fired from an IMU sensor or the RTC, advertises for an x amount of seconds and re-enters STOP mode until the next interrupt request is issued. The onboard LED blinks when the board enters Advertisement mode and when it becomes stuck, the led stays permanently on and the device becomes unresponsive.
The core part of the app is the following FSM
case APP_MAIN_MSG_SLEEP_READY:
MAIN_LOG_INFO("[CPU] All modules idle. Authorizing STOP entry...");
// --- Final pre-sleep housekeeping (only if we are actually meant to sleep) ---
if (main_state == MAIN_STATE_PREPARE_SLEEP) {
PLT_THREAD_SLEEP(10);
svc_rtc_restart(); // ← arm WUT: FULL period counts from NOW
svc_rtc_start_sleep_time(); // ← timestamp for power measurement
// --- Raise the LAST idle flag -> PWR_GATE_ALL_IDLE -> STOP ---
app_power_mark_idle(PWR_GATE_MAIN);
// --- Commit the real transition now that everyone is parked ---
main_state = MAIN_STATE_SLEEP;
} else {
// --- Peripherals idle but device is ACTIVE: do NOT sleep ---
MAIN_LOG_DBG("[CPU] Modules idle but state != SLEEP. Ignoring.");
}
break;
case APP_MAIN_MSG_SENSOR_TRIGGERED:
MAIN_LOG_WARN("[CPU] Sensor Triggered.");
svc_rtc_disable(); // stop WUT so it can't fire during adv
// --- Notify [BLE] API to start Advertising ---
uint8_t result1 = app_api_main_start_adv();
if (result1 == 0) {
uint32_t slept_ms_tr = svc_rtc_sleep_elapsed_time_ms();
MAIN_LOG_INFO("[CPU] Sleep duration = %d ms",slept_ms_tr);
MAIN_LOG_WARN("[CPU] Advertisment Started!");
} else {
MAIN_LOG_WARN("[CPU] Already Advertising. Ignoring...");
}
// MAIN_LOG_INFO("[CPU] Sleeping again");
// svc_rtc_start_sleep_time(); //reset timer, prevent accumulation
//
// //--- Signal [POWER] Module to Enter STOP mode ---
while (!__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TC)) { } // Flush Tx buffers befir entering sleep
app_power_mark_idle(PWR_GATE_MAIN);
break;
case APP_MAIN_MSG_BLE_RST_ADV:
MAIN_LOG_INFO("[CPU] Received BLE Reset Advertisment.");
APP_BLE_ConnStatus_t ble_status = get_ble_status();
if (ble_status != APP_BLE_CONNECTED_CLIENT) {
MAIN_LOG_INFO("[CPU] Sleeping again");
svc_rtc_restart(); // ← arm WUT: FULL period counts from NOW
svc_rtc_start_sleep_time(); // ← timestamp for power measurement
while (!__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TC)) { } // Flush Tx buffers befir entering sleep
app_power_mark_idle(PWR_GATE_MAIN);
}
break;
case APP_MAIN_MSG_SVC_CHECK:
MAIN_LOG_WARN("[CPU] Checking Heartbeats.");
break;
case APP_MAIN_MSG_PERIOD_WKUP:
svc_rtc_disable(); // RTC Doesn't fire while attempting to advertising
MAIN_LOG_INFO("[CPU] Received Periodic Wakeup Event.");
// --- Notify [BLE] API to start Advertising ---
uint8_t result2 = app_api_main_start_adv();
if (result2 == 0) {
uint32_t slept_ms = svc_rtc_sleep_elapsed_time_ms();
MAIN_LOG_INFO("[CPU] Sleep duration = %d ms",slept_ms);
MAIN_LOG_WARN("[CPU] Advertisment Started!");
} else {
MAIN_LOG_WARN("[CPU] Already Advertising. Ignoring...");
}
//MAIN_LOG_INFO("[CPU] Sleeping again");
// --- Signal [POWER] Module to Enter STOP mode ---
while (!__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TC)) { } // Flush Tx buffers befir entering sleep
app_power_mark_idle(PWR_GATE_MAIN);
break;
The rtc service functions used are the following
uint8_t svc_rtc_arm(void) {
if (rtc_state == RTC_STATE_ACTIVE) {
return 1;
}
// --- Set [RTC] State to <ACTIVE> ---
rtc_state = RTC_STATE_ACTIVE;
uint8_t arm_result = 0;
arm_result = HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, RTC_WKUP_PERIOD - 1U,
RTC_WAKEUPCLOCK_RTCCLK_DIV16, 0);
return arm_result;
}
void svc_rtc_restart(void) {
UINT posture = tx_interrupt_control(TX_INT_DISABLE);
wake_counter = 0;
HAL_RTCEx_DeactivateWakeUpTimer(&hrtc);
__HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(&hrtc, RTC_FLAG_WUTF);
if (rtc_wakeups != 0) {
rtc_state = RTC_STATE_ACTIVE;
(void) HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, RTC_WKUP_PERIOD - 1U,
RTC_WAKEUPCLOCK_RTCCLK_DIV16, 0);
} else {
rtc_state = RTC_STATE_IDLE;
}
tx_interrupt_control(posture);
}
uint8_t svc_rtc_disable(void) {
// --- Set [RTC] State to <IDLE> ---
rtc_state = RTC_STATE_IDLE;
uint8_t disable_result = 0;
disable_result = HAL_RTCEx_DeactivateWakeUpTimer(&hrtc);
return disable_result;
}
void svc_rtc_start_sleep_time(void) {
sleep_start = (uint32_t) READ_REG(RTC->SSR);
}
uint32_t svc_rtc_sleep_elapsed_time_ms(void) {
uint32_t now = (uint32_t) READ_REG(RTC->SSR);
uint32_t ticks = sleep_start - now;
return (ticks * 1000U) / RTC_SUBSEC_HZ;
}
-
Does the BLE stack (link layer / timer server) use the RTC wakeup timer or RTC alarms internally?
-
Does reprogramming the rtc cause synchronization issues on the BLE stack (Staying permanently on ADV Mode). If so:
- What is the recommended way to implement a long, configurable periodic wake from STOP mode? Should i move to LPTIM Wake up instead ?
