-
Notifications
You must be signed in to change notification settings - Fork 7.8k
STM32WB0x: Add PM support (suspend-to-ram) #94402
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Fix the improper use of CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC for some STM32WB0 drivers due to the misunderstanding of its definition. Signed-off-by: Ali Hozhabri <[email protected]>
Provide radio timer driver for STM32WB0x SoCs. Signed-off-by: Ali Hozhabri <[email protected]>
Use radio timer as the system timer when Bluetooth is used. Modify CMakeLists.txt to compile radio timer driver when STM32_RADIO_TIMER is enabled. Remove the common parts from hci_stm32wb0.c that are present in the radio timer driver. Set the appropriate value for SYS_CLOCK_HW_CYCLES_PER_SEC and SYS_CLOCK_TICKS_PER_SEC. Signed-off-by: Ali Hozhabri <[email protected]>
Provide PM support, specifically suspend-to-ram, for STM32WB0x. Enable STM32_RADIO_TIMER Kconfig parameter when PM is set. Signed-off-by: Ali Hozhabri <[email protected]>
Enable UART wake-up line in STM32 driver. Signed-off-by: Ali Hozhabri <[email protected]>
Add PM support to the STM32WB0x Bluetooth HCI driver. Implement PM event register to wake up the device for its BLE events. Signed-off-by: Ali Hozhabri <[email protected]>
Optimize power consumption for the Nucleo-WB09KE board by implementing correct pull-up/pull-down configurations when the device enters lower power states. Signed-off-by: Ali Hozhabri <[email protected]>
config SYS_CLOCK_HW_CYCLES_PER_SEC | ||
default 409600 | ||
depends on STM32_RADIO_TIMER |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
get this from a dts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a software timer and there is no crystal running at this frequency that's why it is set in Kconfig. What do you think now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hardware timer with software configurability? That can be represented in dts, it's going through a hardware block
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me explain more:
SYS_CLOCK_HW_CYCLES_PER_SEC=409600
is the system time unit (STU). One STU is equal to 625/256 μs (about 2.4414 μs). It is independent to the hardware oscillator variation. Every timeout event is expressed in STU. Only before programming the real counter, the time expressed in STU is converted to the hardware timer counting unit internally from the radio timer driver.
Do you still think that it should be defined in a DTS file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so then the radio timer driver is wrong? This value should be the hardware cycles per second, as the name implies, there shouldn't be some software translation in a radio driver that changes this into the actual value that the hardware uses, it should be using the hardware value directly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we use the LSE (low-speed external 32.768 kHz), the SYS_CLOCK_HW_CYCLES_PER_SEC can be calculated and is well known. However, when using the LSI (low-speed internal), this value varies because the clock frequency is unknown and differs between devices within a certain range. In our Bluetooth protocol implementation, it is easier to use the STU, which is fixed and independent of both LSI and LSE. We manage internally this value according to the different HW configuration.
return 0; | ||
} | ||
|
||
SYS_INIT(board_pupd_init, PRE_KERNEL_2, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use
zephyr/include/zephyr/platform/hooks.h
Line 70 in 965bcd6
void board_early_init_hook(void); |
Also, this should be in the SoC hook.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why should it be in the SoC hook? Would you please explain more?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The operations performed appear to not be board specific.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No. These power pull-up/pull-down configurations are board specific.
static struct k_work_delayable hal_radio_timer_work, ble_stack_work; | ||
static struct k_work_delayable ble_stack_work; | ||
|
||
#if CONFIG_PM_DEVICE |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#if CONFIG_PM_DEVICE | |
#ifdef CONFIG_PM_DEVICE |
apply everywhere for Kconfig symbols
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which style do you suggest? #ifdef
or #if defined()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which style do you suggest?
#ifdef
or#if defined()
?
either is fine.
#elif defined(IS_UART_WAKEUP_FROMSTOP_INSTANCE) | ||
if (wakeup_line != STM32_WAKEUP_LINE_NONE) { | ||
/* Enable EXTI line associated to UART wake-up event */ | ||
LL_EXTI_EnableIT_0_31(BIT(wakeup_line)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use the STM32 EXTI API in include/zephyr/drivers/interrupt_controller/intc_exti_stm32.h
* Things that need to be preserved across Deepstop, but | ||
* have no associated driver to backup and restore them. | ||
*/ | ||
#define SRAM DT_CHOSEN(zephyr_sram) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#define SRAM DT_CHOSEN(zephyr_sram) | |
#define STM32WB0_SRAM DT_CHOSEN(zephyr_sram) |
|
||
#define RCC_CSR (DT_REG_ADDR(DT_NODELABEL(rcc)) + 0x94) | ||
#define PWR_BASE DT_REG_ADDR(DT_NODELABEL(pwrc)) | ||
#define PWR_SR1 0x10 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#define PWR_SR1 0x10 | |
#define STM32WB0_PWR_SR1 0x10 |
|
||
#if CONFIG_PM_DEVICE | ||
/* ST Proprietary extended event */ | ||
#define HCI_EXT_EVT 0x82 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#define HCI_EXT_EVT 0x82 | |
#define STM32_HCI_EXT_EVT 0x82 |
/* ST Proprietary extended event */ | ||
#define HCI_EXT_EVT 0x82 | ||
#define ACI_HAL_END_OF_RADIO_ACTIVITY_VSEVT_CODE 0x0004 | ||
#define STATE_ALL_BITMASK 0xFFFF |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#define STATE_ALL_BITMASK 0xFFFF | |
#define STM32_STATE_ALL_BITMASK 0xFFFF |
#define HCI_EXT_EVT 0x82 | ||
#define ACI_HAL_END_OF_RADIO_ACTIVITY_VSEVT_CODE 0x0004 | ||
#define STATE_ALL_BITMASK 0xFFFF | ||
#define STATE_IDLE 0x00 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#define STATE_IDLE 0x00 | |
#define STM32_STATE_IDLE 0x00 |
|
||
/* Construct net_buf from event data */ | ||
buf = get_rx(buffer_out); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the NULL check should be 1st, and it should result in a panic or reset or something if it's not excepted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand the purpose of "the NULL check should be 1st," Can you explain more?
For the second part, you mean to put something like __ASSERT_NO_MSG(buf);
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I meant is
if (buf == NULL) {
LOG_ERR("Buf is null");
Panic/return error if pointer should never be Null
}
/* Handle the received HCI data */
LOG_DBG("New event %p len %u type %u", buf, buf->len, buf->data[0]);
hci->recv(dev, buf);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At the moment, the null check is implemented in the else
. Since the function is void
, it's not returning any error, and also the situation is not critical to panic. So, LOG_ERR
is enough.
Update west.yml to point to the recent changes for hal_stm32. Signed-off-by: Ali Hozhabri <[email protected]>
7e53340
to
be88807
Compare
The following west manifest projects have changed revision in this Pull Request:
⛔ DNM label due to: 1 project with PR revision Note: This message is automatically posted and updated by the Manifest GitHub Action. |
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quick skimming
static int board_pupd_init(void) | ||
{ | ||
LL_PWR_EnableGPIOPullUp(LL_PWR_GPIO_A, | ||
LL_PWR_GPIO_BIT_0| | ||
LL_PWR_GPIO_BIT_1| | ||
LL_PWR_GPIO_BIT_2| | ||
LL_PWR_GPIO_BIT_3); | ||
|
||
LL_PWR_EnableGPIOPullDown(LL_PWR_GPIO_A, | ||
LL_PWR_GPIO_BIT_8| | ||
LL_PWR_GPIO_BIT_9| | ||
LL_PWR_GPIO_BIT_10| | ||
LL_PWR_GPIO_BIT_11); | ||
|
||
LL_PWR_EnableGPIOPullDown(LL_PWR_GPIO_B, | ||
LL_PWR_GPIO_BIT_0| | ||
LL_PWR_GPIO_BIT_3| | ||
LL_PWR_GPIO_BIT_6| | ||
LL_PWR_GPIO_BIT_7); | ||
|
||
LL_PWR_EnableGPIOPullUp(LL_PWR_GPIO_B, | ||
LL_PWR_GPIO_BIT_1| | ||
LL_PWR_GPIO_BIT_2| | ||
LL_PWR_GPIO_BIT_4| | ||
LL_PWR_GPIO_BIT_5| | ||
LL_PWR_GPIO_BIT_14| | ||
LL_PWR_GPIO_BIT_15); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There should be a way to use fts and gpio hog to do this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAIK, gpio hog is used to automatically set a GPIO pin at boot, but in this file these pull-up/pull-down configs are related to PWR register and they will be applied when the SoC enters suspend-to-ram
state. In other words, they are not used in active
state.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, we do keep PWRC_CR1.APC
at default value and configure GPIO pull-up/pull-down via PWR
on WB0 series:
zephyr/drivers/gpio/gpio_stm32.c
Lines 177 to 198 in 80ab4b8
static inline void ll_gpio_set_pin_pull(GPIO_TypeDef *GPIOx, uint32_t Pin, uint32_t Pull) | |
{ | |
#if defined(CONFIG_SOC_SERIES_STM32WB0X) | |
/* On STM32WB0, the PWRC PU/PD control registers should be used instead | |
* of the GPIO controller registers, so we cannot use LL_GPIO_SetPinPull. | |
*/ | |
const uint32_t gpio = (GPIOx == GPIOA) ? LL_PWR_GPIO_A : LL_PWR_GPIO_B; | |
if (Pull == LL_GPIO_PULL_UP) { | |
LL_PWR_EnableGPIOPullUp(gpio, Pin); | |
LL_PWR_DisableGPIOPullDown(gpio, Pin); | |
} else if (Pull == LL_GPIO_PULL_DOWN) { | |
LL_PWR_EnableGPIOPullDown(gpio, Pin); | |
LL_PWR_DisableGPIOPullUp(gpio, Pin); | |
} else if (Pull == LL_GPIO_PULL_NO) { | |
LL_PWR_DisableGPIOPullUp(gpio, Pin); | |
LL_PWR_DisableGPIOPullDown(gpio, Pin); | |
} | |
#else | |
LL_GPIO_SetPinPull(GPIOx, Pin, Pull); | |
#endif /* CONFIG_SOC_SERIES_STM32WB0X */ | |
} |
so this configuration would be applied all the time, as far as I understand. (and most importantly: lost if the application changes the pins' configuration!)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right. So, I should implement these pull-up/pull-down configs in the board's DTS file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. You should use a GPIO hog as suggested by @erwango.
See example here:
zephyr/boards/st/steval_stwinbx1/steval_stwinbx1.dts
Lines 128 to 137 in db15de5
&gpioe { | |
status = "okay"; | |
/* Enable 2.7V Analog LDO */ | |
ldo-enable-gpios { | |
gpio-hog; | |
gpios = <15 GPIO_ACTIVE_HIGH>; | |
output-high; | |
}; | |
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I noticed, it sets the pin state at boot time, and it's not related to pull-up/pull-down configs. It doesn't support bias-pull-up
and bias-pull-down
properties.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you tried using gpios = <xx GPIO_PULL_UP>
/ gpios = <xx GPIO_PULL_DOWN>
? From my understanding of the hog driver, it should work.
imply PM_DEVICE if PM | ||
imply PM_S2RAM | ||
imply PM_S2RAM_CUSTOM_MARKING |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use of imply
make it possible that activation if not done if dependency is not met, w/o any error reported.
When using select an error will be generated if dependencies of selected symbol is not met and hence expected configuration cannot be met.
Is that done on purpose ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean why select ... if ...
is not used instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think using select ... if PM
for all should work.
I may have used imply
to avoid repeating the if PM
.
#define STM32_HCLK_FREQUENCY DT_PROP(DT_NODELABEL(rcc), clock_frequency) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should be able to put that definition in a header somewhere - or in fact, it may already be! - instead of re-defining it in every driver.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about defining it in include/zephyr/dt-bindings/clock/stm32_common_clocks.h
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This header is for DT bindings only, it should just contain (un)packing macros for DT->driver exchanges.
I think placing the definition in <soc.h>
(soc/st/stm32/stm32wb0x/soc.h
) would be acceptable. The header might also be already by drivers too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case, it's only for WB0x. What about other STM32 products?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it could go in here? I was suggesting <soc.h>
because I was a bit worried WB0 that including this file on WB0 would blow up, but now I realize it's actually used and my fears are unjustified 😅
Name should be changed if we place it in the general file, maybe to something like STM32_MAIN_SYSTEM_FREQ
(because it corresponds to AXI frequency on some SoCs).
Note that the definition will be unused on all other STM32 until we clean-up the SYS_CLOCK_HW_CYCLES_PER_SEC mess, which will be done in another PR, hence why having something WB0-specific for now is fine (IMO)
PM_DEVICE_DT_INST_DEFINE(0, ble_pm_action); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move this to the HCI_DEVICE_INIT() macro:
PM_DEVICE_DT_INST_DEFINE(0, ble_pm_action); |
+
#define HCI_DEVICE_INIT(inst) \
+ PM_DEVICE_DT_INST_DEFINE(inst, ble_pm_action);
static struct hci_data hci_data_##inst = { \
}; \
#define HCI_DEVICE_INIT(inst) \ | ||
static struct hci_data hci_data_##inst = { \ | ||
}; \ | ||
DEVICE_DT_INST_DEFINE(inst, NULL, NULL, &hci_data_##inst, NULL, \ | ||
DEVICE_DT_INST_DEFINE(inst, NULL, PM_DEVICE_DT_INST_GET(0), &hci_data_##inst, NULL, \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DEVICE_DT_INST_DEFINE(inst, NULL, PM_DEVICE_DT_INST_GET(0), &hci_data_##inst, NULL, \ | |
DEVICE_DT_INST_DEFINE(inst, NULL, PM_DEVICE_DT_INST_GET(inst), &hci_data_##inst, NULL, \ |
|
||
|
||
BUILD_ASSERT(DT_NODE_HAS_STATUS(DT_NODELABEL(clk_lsi), disabled), | ||
"At the moment, LSI is not supported"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit:
"At the moment, LSI is not supported"); | |
"LSI not supported yet"); |
+ we should check if the slow-clock
property on rcc
is clk_lsi
instead... but that's fine.
imply PM_DEVICE if PM | ||
imply PM_S2RAM | ||
imply PM_S2RAM_CUSTOM_MARKING |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think using select ... if PM
for all should work.
I may have used imply
to avoid repeating the if PM
.
@@ -8,6 +8,18 @@ if SOC_SERIES_STM32WB0X | |||
config NUM_IRQS | |||
default 32 | |||
|
|||
config SYS_CLOCK_HW_CYCLES_PER_SEC |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think putting these directives in a if STM32_RADIO_TIMER
block would yield the same result.
/* Wait to be sure that the Radio Timer is active */ | ||
while (LL_RADIO_TIMER_GetAbsoluteTime(WAKEUP) < 0x10) { | ||
} | ||
HAL_RADIO_TIMER_Init(&VTIMER_InitStruct); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit:
HAL_RADIO_TIMER_Init(&VTIMER_InitStruct); | |
/* Note: Device IRQs are enabled by this function */ | |
HAL_RADIO_TIMER_Init(&VTIMER_InitStruct); |
/* Read RCC and PWRC base from Device Tree */ | ||
#include <zephyr/devicetree.h> | ||
|
||
#define RCC_CSR (DT_REG_ADDR(DT_NODELABEL(rcc)) + 0x94) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there are private definitions to a file, it kinda doesn't matter...
/* | ||
* Check for Deepstop exit on wakeup event: | ||
* - RCC_CSR is zero | ||
* - PWRC.EXTSRR has bit DEEPSTOPF set | ||
* (Redundant => unchecked) | ||
* - Either PWRC_SR1 or PWRC_SR3 is non-zero | ||
* | ||
* Note that we don't have to clear any register since | ||
* they are automatically updated on reset/wake-up. | ||
* | ||
* IMPLEMENTATIONS DETAILS: | ||
* r1 must not be modified and the stack must not be | ||
* used by this function as of writing, due to the | ||
* current implementation of arch_pm_s2ram_resume. | ||
* As such, we can only use r0, r2 and r3 here. | ||
* | ||
* N.B.: r12 is also volatile for the ARM ABI, but it | ||
* cannot be used for most operations on ARMv6-M due | ||
* to 16-bit Thumb limitations, so we might as well | ||
* avoid using it entirely. | ||
*/ | ||
ldr r0, =RCC_CSR | ||
ldr r2, [r0] | ||
cmp r2, #0 | ||
bne not_deepstop_wakeup | ||
|
||
ldr r0, =PWR_BASE | ||
ldr r2, [r0, #PWR_SR1] | ||
ldr r3, [r0, #PWR_SR3] | ||
orrs r2, r2, r3 | ||
beq not_deepstop_wakeup | ||
|
||
/** | ||
* All conditions met: this is a wakeup from Deepstop. | ||
*/ | ||
movs r0, #1 | ||
bx lr | ||
|
||
not_deepstop_wakeup: | ||
movs r0, #0 | ||
bx lr |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/* | |
* Check for Deepstop exit on wakeup event: | |
* - RCC_CSR is zero | |
* - PWRC.EXTSRR has bit DEEPSTOPF set | |
* (Redundant => unchecked) | |
* - Either PWRC_SR1 or PWRC_SR3 is non-zero | |
* | |
* Note that we don't have to clear any register since | |
* they are automatically updated on reset/wake-up. | |
* | |
* IMPLEMENTATIONS DETAILS: | |
* r1 must not be modified and the stack must not be | |
* used by this function as of writing, due to the | |
* current implementation of arch_pm_s2ram_resume. | |
* As such, we can only use r0, r2 and r3 here. | |
* | |
* N.B.: r12 is also volatile for the ARM ABI, but it | |
* cannot be used for most operations on ARMv6-M due | |
* to 16-bit Thumb limitations, so we might as well | |
* avoid using it entirely. | |
*/ | |
ldr r0, =RCC_CSR | |
ldr r2, [r0] | |
cmp r2, #0 | |
bne not_deepstop_wakeup | |
ldr r0, =PWR_BASE | |
ldr r2, [r0, #PWR_SR1] | |
ldr r3, [r0, #PWR_SR3] | |
orrs r2, r2, r3 | |
beq not_deepstop_wakeup | |
/** | |
* All conditions met: this is a wakeup from Deepstop. | |
*/ | |
movs r0, #1 | |
bx lr | |
not_deepstop_wakeup: | |
movs r0, #0 | |
bx lr | |
/* | |
* Check for Deepstop exit on wakeup event: | |
* - RCC_CSR is zero | |
* - PWRC.EXTSRR has bit DEEPSTOPF set | |
* (optional; RCC_CSR check suffices) | |
* - Either PWRC_SR1 or PWRC_SR3 is non-zero | |
* | |
* Note that we don't have to clear any register since | |
* they are automatically updated on reset/wake-up. | |
*/ | |
ldr r0, =RCC_CSR | |
ldr r0, [r0] | |
cmp r0, #0 | |
bne not_deepstop_wakeup | |
ldr r0, =PWR_BASE | |
ldr r1, [r0, #PWR_SR1] | |
ldr r0, [r0, #PWR_SR3] | |
orrs r0, r0, r1 | |
beq not_deepstop_wakeup | |
/* All conditions met: this is a wakeup from Deepstop. */ | |
movs r0, #1 | |
bx lr | |
not_deepstop_wakeup: | |
movs r0, #0 | |
bx lr |
Provide PM support, specifically suspend-to-ram.
Add PM support to the Bluetooth HCI driver.
Optimize power consumption for the Nucleo-WB09KE board.
Provide radio timer driver for STM32WB0x SoCs to be used as the system timer when Bluetooth and/or PM are enabled.
Set the appropriate value for SYS_CLOCK_HW_CYCLES_PER_SEC and
SYS_CLOCK_TICKS_PER_SEC when radio timer is used as the system timer.
Enable UART wake-up line in STM32 driver.
Fix the improper use of CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC for some
STM32WB0 drivers due to the misunderstanding of its definition.
Update west to point to the recent changes for hal_stm32.
Supplementary PR #303.
@mathieuchopstm, thank you for your support in PM.