Skip to content
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

stm32 LPTIM clock with prescaler to adjust the TICKS_PER_SEC #63563

Merged
merged 6 commits into from
Dec 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion boards/arm/b_g474e_dpow1/b_g474e_dpow1.dts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@
status = "okay";
};

&lptim1 {
stm32_lp_tick_source: &lptim1 {
clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>,
<&rcc STM32_SRC_LSI LPTIM1_SEL(1)>;
status = "okay";
Expand Down
2 changes: 1 addition & 1 deletion boards/arm/b_u585i_iot02a/b_u585i_iot02a-common.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
apb3-prescaler = <1>;
};

&lptim1 {
stm32_lp_tick_source: &lptim1 {
clocks = <&rcc STM32_CLOCK_BUS_APB3 0x00000800>,
<&rcc STM32_SRC_LSE LPTIM1_SEL(3)>;
status = "okay";
Expand Down
2 changes: 1 addition & 1 deletion boards/arm/disco_l475_iot1/disco_l475_iot1.dts
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@
};
};

&lptim1 {
stm32_lp_tick_source: &lptim1 {
clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>,
<&rcc STM32_SRC_LSE LPTIM1_SEL(3)>;
status = "okay";
Expand Down
2 changes: 1 addition & 1 deletion boards/arm/lora_e5_dev_board/lora_e5_dev_board.dts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
};
};

&lptim1 {
stm32_lp_tick_source: &lptim1 {
status = "okay";
clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>,
<&rcc STM32_SRC_LSI LPTIM1_SEL(1)>;
Expand Down
2 changes: 1 addition & 1 deletion boards/arm/nucleo_g071rb/nucleo_g071rb.dts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@
};
};

&lptim1 {
stm32_lp_tick_source: &lptim1 {
clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>,
<&rcc STM32_SRC_LSI LPTIM1_SEL(1)>;
status = "okay";
Expand Down
2 changes: 1 addition & 1 deletion boards/arm/nucleo_g0b1re/nucleo_g0b1re.dts
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ zephyr_udc0: &usb {
};
};

&lptim1 {
stm32_lp_tick_source: &lptim1 {
clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>,
<&rcc STM32_SRC_LSI LPTIM1_SEL(1)>;
status = "okay";
Expand Down
2 changes: 1 addition & 1 deletion boards/arm/nucleo_g431rb/nucleo_g431rb.dts
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@
};
};

&lptim1 {
stm32_lp_tick_source: &lptim1 {
clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>,
<&rcc STM32_SRC_LSE LPTIM1_SEL(3)>;
status = "okay";
Expand Down
2 changes: 1 addition & 1 deletion boards/arm/nucleo_g474re/nucleo_g474re.dts
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@
};
};

&lptim1 {
stm32_lp_tick_source: &lptim1 {
clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>,
<&rcc STM32_SRC_LSI LPTIM1_SEL(1)>;
status = "okay";
Expand Down
6 changes: 5 additions & 1 deletion boards/arm/nucleo_l073rz/nucleo_l073rz.dts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,11 @@
apb2-prescaler = <1>;
};

&lptim1 {
stm32_lp_tick_source: &lptim1 {
/*
* LSI freq is 37KHz but stm32_lptim driver is using 32000Hz
* resulting in time running 1.13 faster than reality
*/
clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>,
<&rcc STM32_SRC_LSI LPTIM1_SEL(1)>;
status = "okay";
Expand Down
2 changes: 1 addition & 1 deletion boards/arm/nucleo_l476rg/nucleo_l476rg.dts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
apb2-prescaler = <1>;
};

&lptim1 {
stm32_lp_tick_source: &lptim1 {
clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>,
<&rcc STM32_SRC_LSI LPTIM1_SEL(1)>;
status = "okay";
Expand Down
2 changes: 1 addition & 1 deletion boards/arm/nucleo_wb55rg/nucleo_wb55rg.dts
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@
status = "okay";
};

&lptim1 {
stm32_lp_tick_source: &lptim1 {
clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>,
<&rcc STM32_SRC_LSE LPTIM1_SEL(3)>;
status = "okay";
Expand Down
2 changes: 1 addition & 1 deletion boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@
status = "okay";
};

&lptim1 {
stm32_lp_tick_source: &lptim1 {
clocks = <&rcc STM32_CLOCK_BUS_APB7 0x00000800>,
<&rcc STM32_SRC_LSE LPTIM1_SEL(3)>;
status = "okay";
Expand Down
2 changes: 1 addition & 1 deletion boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@
status = "okay";
};

&lptim1 {
stm32_lp_tick_source: &lptim1 {
clocks = <&rcc STM32_CLOCK_BUS_APB7 0x00000800>,
<&rcc STM32_SRC_LSE LPTIM1_SEL(3)>;
status = "okay";
Expand Down
2 changes: 1 addition & 1 deletion boards/arm/nucleo_wl55jc/nucleo_wl55jc.dts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
status = "okay";
};

&lptim1 {
stm32_lp_tick_source: &lptim1 {
clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>,
<&rcc STM32_SRC_LSI LPTIM1_SEL(1)>;
status = "okay";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
};
};

&lptim1 {
stm32_lp_tick_source: &lptim1 {
clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>,
<&rcc STM32_SRC_LSI LPTIM1_SEL(1)>;
status = "okay";
Expand Down
2 changes: 1 addition & 1 deletion boards/arm/sensortile_box_pro/sensortile_box_pro.dts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@
apb3-prescaler = <1>;
};

&lptim1 {
stm32_lp_tick_source: &lptim1 {
clocks = <&rcc STM32_CLOCK_BUS_APB3 0x00000800>,
<&rcc STM32_SRC_LSE LPTIM1_SEL(3)>;
status = "okay";
Expand Down
2 changes: 1 addition & 1 deletion boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
apb2-prescaler = <1>;
};

&lptim1 {
stm32_lp_tick_source: &lptim1 {
clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>,
<&rcc STM32_SRC_LSE LPTIM1_SEL(3)>;
status = "okay";
Expand Down
2 changes: 1 addition & 1 deletion boards/arm/weact_stm32g431_core/weact_stm32g431_core.dts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@
<&rcc STM32_SRC_LSE RTC_SEL(1)>;
};

&lptim1 {
stm32_lp_tick_source: &lptim1 {
status = "okay";
clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>,
<&rcc STM32_SRC_LSE LPTIM1_SEL(3)>;
Expand Down
10 changes: 10 additions & 0 deletions doc/releases/migration-guide-3.6.rst
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,16 @@ Device Drivers and Device Tree
* - ``DT_INST_BUS_LABEL(inst)``
- ``DT_PROP(DT_BUS(DT_DRV_INST(inst)), label)``

* The :dtcompatible:`st,stm32-lptim` lptim which is selected for counting ticks during
low power modes is identified by **stm32_lp_tick_source** in the device tree as follows.
The stm32_lptim_timer driver has been changed to support this.

.. code-block:: devicetree

stm32_lp_tick_source: &lptim1 {
status = "okay";
};

Power Management
================

Expand Down
53 changes: 37 additions & 16 deletions drivers/timer/stm32_lptim_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,26 @@ static const struct device *const clk_ctrl = DEVICE_DT_GET(STM32_CLOCK_CONTROL_N
* 0xFFFF / (LSE freq (32768Hz) / 128)
*/

static uint32_t lptim_clock_freq = KHZ(32);
static int32_t lptim_time_base;

static uint32_t lptim_clock_freq = CONFIG_STM32_LPTIM_CLOCK;
/* The prescaler given by the DTS and to apply to the lptim_clock_freq */
#define LPTIM_CLOCK_RATIO DT_PROP(DT_DRV_INST(0), st_prescaler)
static uint32_t lptim_clock_presc = DT_PROP(DT_DRV_INST(0), st_prescaler);

#if (CONFIG_STM32_LPTIM_CLOCK_LSI)
erwango marked this conversation as resolved.
Show resolved Hide resolved

/* Kconfig defines the clock source as LSI : check coherency with DTS */
#if (DT_INST_CLOCKS_CELL_BY_IDX(0, 1, bus) != STM32_SRC_LSI)
#warning CONFIG_STM32_LPTIM_CLOCK_LSI requires STM32_SRC_LSI defined as LPTIM domain clock
#endif /* STM32_SRC_LSI */
erwango marked this conversation as resolved.
Show resolved Hide resolved

#elif (CONFIG_STM32_LPTIM_CLOCK_LSE)

/* Kconfig defines the clock source as LSE : check coherency with DTS */
#if (DT_INST_CLOCKS_CELL_BY_IDX(0, 1, bus) != STM32_SRC_LSE)
#warning CONFIG_STM32_LPTIM_CLOCK_LSE requires STM32_SRC_LSE defined as LPTIM domain clock
#endif /* STM32_SRC_LSE */

#endif /* CONFIG_STM32_LPTIM_CLOCK_LSI */

/* Minimum nb of clock cycles to have to set autoreload register correctly */
#define LPTIM_GUARD_VALUE 2
Expand All @@ -81,17 +96,6 @@ static bool autoreload_ready = true;

static struct k_spinlock lock;

/* For tick accuracy, a specific tick to freq ratio is expected */
/* This check assumes LSI@32KHz or LSE@32768Hz */
#if !defined(CONFIG_STM32_LPTIM_TICK_FREQ_RATIO_OVERRIDE)
#if (((DT_CLOCKS_CELL_BY_IDX(DT_DRV_INST(0), 1, bus) == STM32_SRC_LSI) && \
(CONFIG_SYS_CLOCK_TICKS_PER_SEC != 4000)) || \
((DT_CLOCKS_CELL_BY_IDX(DT_DRV_INST(0), 1, bus) == STM32_SRC_LSE) && \
(CONFIG_SYS_CLOCK_TICKS_PER_SEC != 4096)))
#warning Advised tick freq is 4096 for LSE / 4000 for LSI
#endif
#endif /* !CONFIG_STM32_LPTIM_TICK_FREQ_RATIO_OVERRIDE */

static inline bool arrm_state_get(void)
{
return (LL_LPTIM_IsActiveFlag_ARRM(LPTIM) && LL_LPTIM_IsEnabledIT_ARRM(LPTIM));
Expand Down Expand Up @@ -387,8 +391,24 @@ static int sys_clock_driver_init(void)
return -EIO;
}

#if !defined(CONFIG_STM32_LPTIM_TICK_FREQ_RATIO_OVERRIDE)
/*
* Check coherency between CONFIG_SYS_CLOCK_TICKS_PER_SEC
* and the lptim_clock_freq which is the CONFIG_STM32_LPTIM_CLOCK reduced
* by the lptim_clock_presc
*/
if (lptim_clock_presc <= 8) {
__ASSERT(CONFIG_STM32_LPTIM_CLOCK / 8 >= CONFIG_SYS_CLOCK_TICKS_PER_SEC,
"It is recommended to set SYS_CLOCK_TICKS_PER_SEC to CONFIG_STM32_LPTIM_CLOCK/8");
} else {
__ASSERT(CONFIG_STM32_LPTIM_CLOCK / lptim_clock_presc >=
CONFIG_SYS_CLOCK_TICKS_PER_SEC,
"Set SYS_CLOCK_TICKS_PER_SEC to CONFIG_STM32_LPTIM_CLOCK/lptim_clock_presc");
}
#endif /* !CONFIG_STM32_LPTIM_TICK_FREQ_RATIO_OVERRIDE */

/* Actual lptim clock freq when the clock source is reduced by the prescaler */
lptim_clock_freq = lptim_clock_freq / LPTIM_CLOCK_RATIO;
lptim_clock_freq = lptim_clock_freq / lptim_clock_presc;

/* Clear the event flag and possible pending interrupt */
IRQ_CONNECT(DT_INST_IRQN(0),
Expand All @@ -404,7 +424,8 @@ static int sys_clock_driver_init(void)
/* configure the LPTIM counter */
LL_LPTIM_SetClockSource(LPTIM, LL_LPTIM_CLK_SOURCE_INTERNAL);
/* the LPTIM clock freq is affected by the prescaler */
LL_LPTIM_SetPrescaler(LPTIM, (__CLZ(__RBIT(LPTIM_CLOCK_RATIO)) << LPTIM_CFGR_PRESC_Pos));
LL_LPTIM_SetPrescaler(LPTIM, (__CLZ(__RBIT(lptim_clock_presc)) << LPTIM_CFGR_PRESC_Pos));

#if defined(CONFIG_SOC_SERIES_STM32U5X) || \
defined(CONFIG_SOC_SERIES_STM32WBAX)
LL_LPTIM_OC_SetPolarity(LPTIM, LL_LPTIM_CHANNEL_CH1,
Expand Down
8 changes: 7 additions & 1 deletion dts/bindings/timer/st,stm32-lptim.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
# Copyright (c) 2020, STMicroelectronics
# SPDX-License-Identifier: Apache-2.0

description: STM32 lptim
description: |
STM32 lptim : low power timer
The lptim node to be used for counting ticks during lowpower modes
must be named stm32_lp_tick_source in the DTS, as follows:
stm32_lp_tick_source: &lptim1 {
status = "okay";
}

compatible: "st,stm32-lptim"

Expand Down
11 changes: 10 additions & 1 deletion samples/boards/stm32/power_mgmt/blinky/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ Overview
This sample is a minimum application to demonstrate basic power management
behavior in a basic blinking LED set up using the :ref:`GPIO API <gpio_api>` in
low power context.
Note that lptim instance selected for the low power timer is named **&stm32_lp_tick_source**
When setting a prescaler to decrease the lptimer input clock frequency, the system can sleep
for a longer timeout value and the CONFIG_SYS_CLOCK_TICKS_PER_SEC is adjusted.
For example, when clocking the low power Timer with LSE clock at 32768Hz and adding a
prescaler of <32>, then the kernel sleep period can reach 65536 * 32/32768 = 64 seconds
CONFIG_SYS_CLOCK_TICKS_PER_SEC is set to 1024.

.. _stm32-pm-blinky-sample-requirements:

Expand All @@ -30,7 +36,10 @@ Build and flash Blinky as follows, changing ``stm32l562e_dk`` for your board:
:goals: build flash
:compact:

After flashing, the LED starts to blink.
After flashing, the LED starts to blink with a fixed period (SLEEP_TIME_MS).
When LPTIM input clock has a prescaler, longer perdiod (up to 64 seconds)
of low power can be tested.


PM configurations
*****************
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* give a prescaler to the lptim clock : LSE / 16 = 2048Hz
* so that the sleep period is of 32s in the sample application
* with a LPTIM1 prescaler of <1> to <8>, CONFIG_SYS_CLOCK_TICKS_PER_SEC is 4096
* with a LPTIM1 prescaler >= <16>, CONFIG_SYS_CLOCK_TICKS_PER_SEC is LSE / prescaler
*/
&stm32_lp_tick_source {
st,prescaler = <16>;
};
gautierg-st marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/*
* give a prescaler to the lptim clock : LSE / 32 = 1024Hz
* so that the sleep period is of 64s in the sample application
*
* with a LPTIM1 prescaler of <1> to <8>, CONFIG_SYS_CLOCK_TICKS_PER_SEC is 4096
* with a LPTIM1 prescaler >= <16>, CONFIG_SYS_CLOCK_TICKS_PER_SEC is LSE / prescaler
*/

&lptim1 {
&stm32_lp_tick_source {
st,prescaler = <32>;
};
1 change: 1 addition & 0 deletions samples/boards/stm32/power_mgmt/blinky/prj.conf
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ CONFIG_PM=y
CONFIG_PM_DEVICE=y
CONFIG_PM_DEVICE_RUNTIME=y
CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE=n
CONFIG_ASSERT=y
21 changes: 19 additions & 2 deletions soc/arm/st_stm32/common/Kconfig.defconfig.series
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ config CORTEX_M_SYSTICK
DT_STM32_RCC_PATH := $(dt_nodelabel_path,rcc)
DT_STM32_RCC_CLOCK_FREQ := $(dt_node_int_prop_int,$(DT_STM32_RCC_PATH),clock-frequency)

DT_ST_PRESCALER := st,prescaler
DT_STM32_LPTIM_PATH := $(dt_nodelabel_path,stm32_lp_tick_source)

config SYS_CLOCK_HW_CYCLES_PER_SEC
default "$(DT_STM32_RCC_CLOCK_FREQ)" if "$(dt_nodelabel_enabled,rcc)"

Expand All @@ -24,9 +27,23 @@ config LOG_BACKEND_SWO_REF_FREQ_HZ
endif # LOG_BACKEND_SWO

# set the tick per sec as a divider of the LPTIM clock source
# with a minimum value of 4096 for SYS_CLOCK_TICKS_PER_SEC to keep
# SYS_CLOCK_TICKS_PER_SEC not too high compared to the LPTIM counter clock
config SYS_CLOCK_TICKS_PER_SEC
default 4096 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" < 16
erwango marked this conversation as resolved.
Show resolved Hide resolved
default 2048 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" = 16
default 1024 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" = 32
default 512 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" = 64
default 256 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" = 128
depends on STM32_LPTIM_TIMER && STM32_LPTIM_CLOCK_LSE
erwango marked this conversation as resolved.
Show resolved Hide resolved

config SYS_CLOCK_TICKS_PER_SEC
default 4096 if STM32_LPTIM_TIMER && STM32_LPTIM_CLOCK_LSE
default 4000 if STM32_LPTIM_TIMER && STM32_LPTIM_CLOCK_LSI
default 4000 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" < 16
default 2000 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" = 16
default 1000 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" = 32
default 500 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" = 64
default 250 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" = 128
depends on STM32_LPTIM_TIMER && STM32_LPTIM_CLOCK_LSI

config CLOCK_CONTROL_STM32_CUBE
default y
Expand Down
Loading