cancel
Showing results for 
Search instead for 
Did you mean: 

Stop mode on Threadx with BLE on WBA

AlexES
Associate III

Hello. I'm working on a BLE  application that uses an STM WBA55 board and ThreadX. It was based on the St Threadx p2pServer example, The Sequencer is disabled. I'm using stmCubeIDE 1.19 and st_fw1.7 and i cannot migrate to new versions due to compatibility reasons.

The main idea for the application is that the board initializes, advertizes 10-20 seconds for a connection, connects to a device like a phone pc, gets data from a sensor and transfers the data to the connected device. If no connection occurs or if the device is disconnected it should go into sleep/stop/standby mode until an EXTI interrupt from the user button is triggered. 


As of now the application is structured as follows:


-- A main thread is in charge of initializing the rest of the threads (one thread for each type of sensor eg temp adc etc) and handle events like ble connection/disconnection and sleep/wake up requests.
--Upon a sleep request a flag is set into an appropriate value. The rest of the threads include an fsm where if the flag is true, they will just sleep. In addition the board peripherals like UART, I2C, etc are de-initialied and interrupts other than the desirable EXTI line are disabled. 
--On the EXTI event, the peripherals are re-initialized and the device advertizes for a new connection once more. 

I tried the low power examples from ST. The bare metal Stop1 examples worked perfectly. The power consumption dropped to a couple of μΑ once the device went into stop mode. The ThreadX example didn't seem to work as expected though. I trie the example as is and only managed to drop the consumption to a couple of mAs which is very high. I switched the macros to the appropriate ones for stop mode instead of low power but got the same results. 

So, long story short my question is how can i integrate stop mode on my application right now ? The examples either use sleep on threadx or BLE but not on an application that uses both. 


-- What setting do i need to configure (.ioc and header files)?

-- What functions do i need to use (is HAL_PWR_EnterSTOPMode(PWR_LOWPOWERMODE_STOP1, PWR_STOPENTRY_WFI); enough once all interrupt sources are disabled? )?

-- What is the overall power consumption that i should expect on stop mode? A couple of hundreds of μΑs ?

 

 

2 REPLIES 2
Imen.D
ST Employee

Hello  ,

I advise starting from ready-to-use CubeMx application available under STM32CubeWBA MCU package: 

Calling HAL_PWR_EnterSTOPMode(PWR_LOWPOWERMODE_STOP1, PWR_STOPENTRY_WFI); is sufficient to enter STOP mode, with system configuration steps (including GPIO and SysTick configuration). 

Before entering STOP mode, suspend the SysTick timer with HAL_SuspendTick() to prevent unwanted wakeups.

Please refer to this article STM32CubeWBA: Low-power management - stm32mcu and AN6159 (page 28), to have more visibility about the system configuration, main clock sources and parameters required to configure.

The STM32WBA5x datasheet related to your device will be your support for more details about the power consumption, on section 5.3.8 Supply current characteristics.

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen

Hello. The thing is that this example is using the sequencer. I use threadx without the sequencer. This is a snippet from my project to show you what i do when i want my device to enter STOP1 mode. 

static uint8_t app_main_peripherals_sleep() {
	uint8_t ret = 0;
	app_main_reset_adv();
	ret = app_main_i2c_sleep(&hi2c1);
	if (ret != 0)
		return ret;

	tx_thread_sleep(ms_to_ticks(10));

	ret = app_main_uart_sleep(&huart1);
	if (ret != 0)
		return ret;

	tx_thread_sleep(ms_to_ticks(10));

	ret = app_main_gpio_sleep();
	if (ret != 0)
		return ret;

	tx_thread_sleep(ms_to_ticks(10));

	return ret;
}

static uint8_t app_main_gpio_sleep(void) {
	GPIO_InitTypeDef GPIO_InitStruct = { 0 };

	__HAL_RCC_GPIOA_CLK_ENABLE();
	__HAL_RCC_GPIOB_CLK_ENABLE();
	__HAL_RCC_GPIOC_CLK_ENABLE();

	/* 1. Set all pins to analog (low power) */
	GPIO_InitStruct.Pin = GPIO_PIN_All;
	GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
	GPIO_InitStruct.Pull = GPIO_NOPULL;

	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
	HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

	/* 2. Reconfigure wake-up pins */
	GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_5;
	GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

	/* 3. CRITICAL: Clear EXTI flags */
	__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);
	__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_5);

	/* 4. CRITICAL: Enable NVIC interrupts */
	HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);
	HAL_NVIC_EnableIRQ(EXTI0_IRQn);

	HAL_NVIC_SetPriority(EXTI5_IRQn, 0, 0);
	HAL_NVIC_EnableIRQ(EXTI5_IRQn);

	return 0;
}

static uint8_t app_main_uart_sleep(UART_HandleTypeDef *huart) {
	HAL_StatusTypeDef ret;

	/* Abort ongoing transfers */
	HAL_UART_Abort(huart);

	if (huart->hdmatx != NULL) {
		HAL_DMA_Abort(huart->hdmatx);
		HAL_DMA_DeInit(huart->hdmatx);
	}

	if (huart->hdmarx != NULL) {
		HAL_DMA_Abort(huart->hdmarx);
		HAL_DMA_DeInit(huart->hdmarx);
	}

	/* Disable IRQs */
	HAL_NVIC_DisableIRQ(USART1_IRQn);

	/* Deinit UART */
	ret = HAL_UART_DeInit(huart);
	if (ret != HAL_OK) {
		MAIN_ERR("[UART] DeInit failed");
		return ret;
	}
	Log_Module_DeInit();
	/* Disable clock */
	__HAL_RCC_USART1_CLK_DISABLE();

	MAIN_INFO("[UART] Entered low power");

	return HAL_OK;
}
static uint8_t app_main_i2c_sleep(I2C_HandleTypeDef *hi2c) {

	UINT status;
	HAL_StatusTypeDef ret;
	status = tx_mutex_get(&i2cMutex, TX_WAIT_FOREVER);

	if (status != TX_SUCCESS) {
		MAIN_ERR("[CPU] Failed to acquire I2C Mutex: <%d>.", status);
		return status;
	}
	HAL_I2C_Master_Abort_IT(hi2c, 0x00);

	if (hi2c->hdmatx != NULL) {
		HAL_DMA_Abort(hi2c->hdmatx);
		HAL_DMA_DeInit(hi2c->hdmatx);
	}

	if (hi2c->hdmarx != NULL) {
		HAL_DMA_Abort(hi2c->hdmarx);
		HAL_DMA_DeInit(hi2c->hdmarx);
	}

	HAL_NVIC_DisableIRQ(I2C1_ER_IRQn);
	ret = HAL_I2C_DeInit(hi2c);
	if (ret != HAL_OK) {
		MAIN_ERR("[I2C] DeInit failed: 0x%08X", ret);
		tx_mutex_put(&i2cMutex);
		return ret;
	}

	__HAL_RCC_I2C1_CLK_DISABLE();

	tx_mutex_put(&i2cMutex);

	MAIN_INFO("[I2C] Entered low power state");

	return status;

}
void enter_stop1_mode(void)
{
    // 1. Stop BLE advertising
    APP_BLE_Procedure_Gap_Peripheral(PROC_GAP_PERIPH_ADVERTISE_STOP);
    app_main_peripherals_sleep();

    // 2. Suspend SysTick (IMPORTANT)
    HAL_SuspendTick();

    // 4. Clear power flags
    LL_PWR_ClearFlag_STOP();
    LL_RCC_ClearResetFlags();

    // 5. Select STOP1
    LL_PWR_SetPowerMode(LL_PWR_MODE_STOP1);

    // 6. Enable deep sleep
    LL_LPM_EnableDeepSleep();

    // 7. ENTER STOP MODE
    __WFI();

    // ===== wakes up here =====

    // 8. Disable deep sleep
    LL_LPM_EnableSleep();

    // 9. Restore clock
    SystemClock_Config();

    // 10. Resume SysTick
    HAL_ResumeTick();

   
}


The peripherals do indeed "go to sleep", but the device never enters stop mode. I use a power profiler peripheral to meassure power consumption and it never goes below 4~4 mAmps. In addition these functions are executed when the rest of the threads are in a constant thread sleep state