From 66a7a0a0656231046ffe7068cf67abee6c953620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20H=C3=BC=C3=9Fler?= Date: Sat, 19 Feb 2022 17:26:21 +0100 Subject: [PATCH 1/6] drivers/periph: add VBAT interface --- drivers/include/periph/vbat.h | 72 +++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 drivers/include/periph/vbat.h diff --git a/drivers/include/periph/vbat.h b/drivers/include/periph/vbat.h new file mode 100644 index 0000000000..4156ae192c --- /dev/null +++ b/drivers/include/periph/vbat.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2022 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup drivers_periph_vbat backup battery monitoring + * @ingroup drivers_periph + * @brief Driver to monitor the internal backup battery status + * + * The backup battery must be connected with the VBAT pin and GND. + * On most development boards you will have to remove a solder bridge + * that connects VDD with VBAT. The battery is used to retain the backup domain + * register and RTC register content while power (VDD) is off. + * + * The actual driver is implemented as a CPU feature. + * A board that supports + * backup battery monitoring via ADC, must `#define VBAT_ADC ADC_LINE(x)`, + * where `x` is the index of the internal VBAT ADC line in `adc_config[]` + * in periph_conf.h. + * + * @{ + * + * @file + * @brief Interface of backup battery (VBAT) monitoring + * + * @author Fabian Hüßler + */ + +#ifndef PERIPH_VBAT_H +#define PERIPH_VBAT_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Initialize backup battery monitoring + * + * @retval != 0: Failure + * @retval 0: Success + */ +int vbat_init(void); + +/** + * @brief Sample backup battery + * + * @return Backup battery load in mV + */ +int32_t vbat_sample_mv(void); + +/** + * @brief Sample the backup battery and compare the result with + * the minimum value required to power the backup domain + * + * @retval true: empty + * @retval false: not empty + */ +bool vbat_is_empty(void); + +#ifdef __cplusplus +} +#endif + +#endif /* PERIPH_VBAT_H */ +/** @} */ From 33c2944076b2d4320bb7a3848b37b9c64d3194ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20H=C3=BC=C3=9Fler?= Date: Tue, 12 Oct 2021 13:16:57 +0200 Subject: [PATCH 2/6] cpu/stm32: add VBAT for stm32 --- cpu/stm32/Makefile.dep | 3 + cpu/stm32/Makefile.features | 19 ++ cpu/stm32/include/periph/cpu_vbat.h | 41 ++++ cpu/stm32/include/periph/f0/periph_cpu.h | 9 + cpu/stm32/include/periph/f2/periph_cpu.h | 9 + cpu/stm32/include/periph/f3/periph_cpu.h | 9 + cpu/stm32/include/periph/f4/periph_cpu.h | 9 + cpu/stm32/include/periph/f7/periph_cpu.h | 9 + cpu/stm32/include/periph/g0/periph_cpu.h | 8 + cpu/stm32/include/periph/g4/periph_cpu.h | 8 + cpu/stm32/include/periph/l4/periph_cpu.h | 9 + cpu/stm32/include/periph/l5/periph_cpu.h | 8 + cpu/stm32/include/periph/u5/periph_cpu.h | 8 + cpu/stm32/include/periph/wb/periph_cpu.h | 8 + cpu/stm32/include/periph/wl/periph_cpu.h | 8 + cpu/stm32/include/periph_cpu.h | 1 + cpu/stm32/kconfigs/f0/Kconfig.lines | 11 ++ cpu/stm32/kconfigs/f2/Kconfig | 1 + cpu/stm32/kconfigs/f3/Kconfig | 1 + cpu/stm32/kconfigs/f4/Kconfig | 1 + cpu/stm32/kconfigs/f7/Kconfig | 1 + cpu/stm32/kconfigs/g0/Kconfig | 1 + cpu/stm32/kconfigs/g4/Kconfig | 1 + cpu/stm32/kconfigs/l4/Kconfig | 1 + cpu/stm32/kconfigs/l5/Kconfig | 1 + cpu/stm32/kconfigs/u5/Kconfig | 1 + cpu/stm32/kconfigs/wb/Kconfig | 1 + cpu/stm32/kconfigs/wl/Kconfig | 1 + cpu/stm32/periph/adc_f0_g0.c | 22 ++- cpu/stm32/periph/adc_f2.c | 43 +++-- cpu/stm32/periph/adc_f3.c | 23 ++- cpu/stm32/periph/adc_f4_f7.c | 22 ++- cpu/stm32/periph/adc_l4.c | 23 ++- cpu/stm32/periph/adc_wl.c | 22 ++- cpu/stm32/periph/vbat.c | 230 +++++++++++++++++++++++ drivers/periph_common/Kconfig | 1 + drivers/periph_common/Kconfig.vbat | 39 ++++ kconfigs/Kconfig.features | 5 + 38 files changed, 593 insertions(+), 25 deletions(-) create mode 100644 cpu/stm32/include/periph/cpu_vbat.h create mode 100644 cpu/stm32/periph/vbat.c create mode 100644 drivers/periph_common/Kconfig.vbat diff --git a/cpu/stm32/Makefile.dep b/cpu/stm32/Makefile.dep index 431f89a060..505b1289a2 100644 --- a/cpu/stm32/Makefile.dep +++ b/cpu/stm32/Makefile.dep @@ -49,5 +49,8 @@ ifneq (,$(filter periph_adc,$(FEATURES_USED))) endif endif +ifneq (,$(filter periph_vbat,$(USEMODULE))) + FEATURES_REQUIRED += periph_adc +endif include $(RIOTCPU)/cortexm_common/Makefile.dep diff --git a/cpu/stm32/Makefile.features b/cpu/stm32/Makefile.features index ddaf3312aa..3ebfa16edb 100644 --- a/cpu/stm32/Makefile.features +++ b/cpu/stm32/Makefile.features @@ -34,6 +34,25 @@ ifneq (,$(filter $(STM32_WITH_BKPRAM),$(CPU_MODEL))) FEATURES_PROVIDED += backup_ram endif +STM32_WITH_VBAT = stm32f031% stm32f038% stm32f042% stm32f048% \ + stm32f051% stm32f058% stm32f071% stm32f072% \ + stm32f078% stm32f091% stm32f098% \ + stm32f2% \ + stm32f3% \ + stm32f4% \ + stm32f7% \ + stm32g0% \ + stm32g4% stm32gbk1cb \ + stm32l4% \ + stm32l5% \ + stm32u5% \ + stm32wb% \ + stm32wl% + +ifneq (,$(filter $(STM32_WITH_VBAT),$(CPU_MODEL))) + FEATURES_PROVIDED += periph_vbat +endif + # The f2, f4 and f7 do not support the pagewise api ifneq (,$(filter $(CPU_FAM),f2 f4 f7)) FEATURES_PROVIDED += periph_flashpage diff --git a/cpu/stm32/include/periph/cpu_vbat.h b/cpu/stm32/include/periph/cpu_vbat.h new file mode 100644 index 0000000000..082d6a14b4 --- /dev/null +++ b/cpu/stm32/include/periph/cpu_vbat.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2022 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_stm32 + * @{ + * + * @file + * @brief CPU internal VBAT interface and definitions of the STM32 family + * + * @author Fabian Hüßler + */ + +#ifndef PERIPH_CPU_VBAT_H +#define PERIPH_CPU_VBAT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Enable the VBAT sampling channel + */ +void vbat_enable(void); + +/** + * @brief Disable the VBAT sampling channel + */ +void vbat_disable(void); + +#ifdef __cplusplus +} +#endif + +#endif /* PERIPH_CPU_VBAT_H */ +/** @} */ diff --git a/cpu/stm32/include/periph/f0/periph_cpu.h b/cpu/stm32/include/periph/f0/periph_cpu.h index 5b0e21a9e7..f8202c1798 100644 --- a/cpu/stm32/include/periph/f0/periph_cpu.h +++ b/cpu/stm32/include/periph/f0/periph_cpu.h @@ -61,6 +61,15 @@ typedef enum { ADC_RES_16BIT = (0xff) /**< not applicable */ } adc_res_t; /** @} */ + +/** + * @name Constants for internal VBAT ADC line + * @{ + */ +#define VBAT_ADC_RES ADC_RES_12BIT +#define VBAT_ADC_MAX 4095 +/** @} */ + #endif /* ndef DOXYGEN */ #ifdef __cplusplus diff --git a/cpu/stm32/include/periph/f2/periph_cpu.h b/cpu/stm32/include/periph/f2/periph_cpu.h index 5e82d3d254..598dfbc3b5 100644 --- a/cpu/stm32/include/periph/f2/periph_cpu.h +++ b/cpu/stm32/include/periph/f2/periph_cpu.h @@ -58,6 +58,15 @@ typedef enum { ADC_RES_16BIT = 2 /**< ADC resolution: 16 bit (not supported)*/ } adc_res_t; /** @} */ + +/** + * @name Constants for internal VBAT ADC line + * @{ + */ +#define VBAT_ADC_RES ADC_RES_12BIT +#define VBAT_ADC_MAX 4095 +/** @} */ + #endif /* ndef DOXYGEN */ #ifdef __cplusplus diff --git a/cpu/stm32/include/periph/f3/periph_cpu.h b/cpu/stm32/include/periph/f3/periph_cpu.h index 69df093792..01ccf69573 100644 --- a/cpu/stm32/include/periph/f3/periph_cpu.h +++ b/cpu/stm32/include/periph/f3/periph_cpu.h @@ -69,6 +69,15 @@ typedef enum { ADC_RES_16BIT = (0x2) /**< not applicable */ } adc_res_t; /** @} */ + +/** + * @name Constants for internal VBAT ADC line + * @{ + */ +#define VBAT_ADC_RES ADC_RES_12BIT +#define VBAT_ADC_MAX 4095 +/** @} */ + #endif /* ndef DOXYGEN */ #ifdef __cplusplus diff --git a/cpu/stm32/include/periph/f4/periph_cpu.h b/cpu/stm32/include/periph/f4/periph_cpu.h index 9318082c13..adba5e27be 100644 --- a/cpu/stm32/include/periph/f4/periph_cpu.h +++ b/cpu/stm32/include/periph/f4/periph_cpu.h @@ -69,6 +69,15 @@ typedef enum { ADC_RES_16BIT = 2 /**< ADC resolution: 16 bit (not supported)*/ } adc_res_t; /** @} */ + +/** + * @name Constants for internal VBAT ADC line + * @{ + */ +#define VBAT_ADC_RES ADC_RES_12BIT +#define VBAT_ADC_MAX 4095 +/** @} */ + #endif /* ndef DOXYGEN */ #ifdef __cplusplus diff --git a/cpu/stm32/include/periph/f7/periph_cpu.h b/cpu/stm32/include/periph/f7/periph_cpu.h index a7c1d5ddd2..742c3bceb7 100644 --- a/cpu/stm32/include/periph/f7/periph_cpu.h +++ b/cpu/stm32/include/periph/f7/periph_cpu.h @@ -52,6 +52,15 @@ typedef enum { ADC_RES_16BIT = 2 /**< ADC resolution: 16 bit (not supported)*/ } adc_res_t; /** @} */ + +/** + * @name Constants for internal VBAT ADC line + * @{ + */ +#define VBAT_ADC_RES ADC_RES_12BIT +#define VBAT_ADC_MAX 4095 +/** @} */ + #endif /* ndef DOXYGEN */ #ifdef __cplusplus diff --git a/cpu/stm32/include/periph/g0/periph_cpu.h b/cpu/stm32/include/periph/g0/periph_cpu.h index 7425c30d61..c325e36f90 100644 --- a/cpu/stm32/include/periph/g0/periph_cpu.h +++ b/cpu/stm32/include/periph/g0/periph_cpu.h @@ -32,6 +32,14 @@ extern "C" { */ #define STM32_BOOTLOADER_ADDR (0x1FFF0000) +/** + * @name Constants for internal VBAT ADC line + * @{ + */ +#define VBAT_ADC_RES ADC_RES_12BIT +#define VBAT_ADC_MAX 4095 +/** @} */ + #endif /* ndef DOXYGEN */ /** diff --git a/cpu/stm32/include/periph/g4/periph_cpu.h b/cpu/stm32/include/periph/g4/periph_cpu.h index bc694f76b2..ad86b3ae7f 100644 --- a/cpu/stm32/include/periph/g4/periph_cpu.h +++ b/cpu/stm32/include/periph/g4/periph_cpu.h @@ -32,6 +32,14 @@ extern "C" { */ #define STM32_BOOTLOADER_ADDR (0x1FFF0000) +/** + * @name Constants for internal VBAT ADC line + * @{ + */ +#define VBAT_ADC_RES ADC_RES_12BIT +#define VBAT_ADC_MAX 4095 +/** @} */ + #endif /* ndef DOXYGEN */ #ifdef __cplusplus diff --git a/cpu/stm32/include/periph/l4/periph_cpu.h b/cpu/stm32/include/periph/l4/periph_cpu.h index 78075b11b0..daa0d78f8e 100644 --- a/cpu/stm32/include/periph/l4/periph_cpu.h +++ b/cpu/stm32/include/periph/l4/periph_cpu.h @@ -63,6 +63,15 @@ typedef enum { ADC_RES_16BIT = (0x2) /**< not applicable */ } adc_res_t; /** @} */ + +/** + * @name Constants for internal VBAT ADC line + * @{ + */ +#define VBAT_ADC_RES ADC_RES_12BIT +#define VBAT_ADC_MAX 4095 +/** @} */ + #endif /* ndef DOXYGEN */ #ifdef __cplusplus diff --git a/cpu/stm32/include/periph/l5/periph_cpu.h b/cpu/stm32/include/periph/l5/periph_cpu.h index 0c3a214a1a..3d47d6a667 100644 --- a/cpu/stm32/include/periph/l5/periph_cpu.h +++ b/cpu/stm32/include/periph/l5/periph_cpu.h @@ -32,6 +32,14 @@ extern "C" { */ #define STM32_BOOTLOADER_ADDR (0x0BF90000) +/** + * @name Constants for internal VBAT ADC line + * @{ + */ +#define VBAT_ADC_RES ADC_RES_12BIT +#define VBAT_ADC_MAX 4095 +/** @} */ + #endif /* ndef DOXYGEN */ #ifdef __cplusplus diff --git a/cpu/stm32/include/periph/u5/periph_cpu.h b/cpu/stm32/include/periph/u5/periph_cpu.h index a5327d4c6e..bdc4c279b6 100644 --- a/cpu/stm32/include/periph/u5/periph_cpu.h +++ b/cpu/stm32/include/periph/u5/periph_cpu.h @@ -32,6 +32,14 @@ extern "C" { */ #define STM32_BOOTLOADER_ADDR (0x0BF90000) +/** + * @name Constants for internal VBAT ADC line + * @{ + */ +#define VBAT_ADC_RES ADC_RES_14BIT +#define VBAT_ADC_MAX 16383 +/** @} */ + #endif /* ndef DOXYGEN */ #ifdef __cplusplus diff --git a/cpu/stm32/include/periph/wb/periph_cpu.h b/cpu/stm32/include/periph/wb/periph_cpu.h index 0928df59e3..f03075e936 100644 --- a/cpu/stm32/include/periph/wb/periph_cpu.h +++ b/cpu/stm32/include/periph/wb/periph_cpu.h @@ -32,6 +32,14 @@ extern "C" { */ #define STM32_BOOTLOADER_ADDR (0x1FFF0000) +/** + * @name Constants for internal VBAT ADC line + * @{ + */ +#define VBAT_ADC_RES ADC_RES_12BIT +#define VBAT_ADC_MAX 4095 +/** @} */ + #endif /* ndef DOXYGEN */ #ifdef __cplusplus diff --git a/cpu/stm32/include/periph/wl/periph_cpu.h b/cpu/stm32/include/periph/wl/periph_cpu.h index 9d676cdd76..8edf765fbb 100644 --- a/cpu/stm32/include/periph/wl/periph_cpu.h +++ b/cpu/stm32/include/periph/wl/periph_cpu.h @@ -57,6 +57,14 @@ typedef enum { */ #define STM32_BOOTLOADER_ADDR (0x1FFF0000) +/** + * @name Constants for internal VBAT ADC line + * @{ + */ +#define VBAT_ADC_RES ADC_RES_12BIT +#define VBAT_ADC_MAX 4095 +/** @} */ + #endif /* ndef DOXYGEN */ /** diff --git a/cpu/stm32/include/periph_cpu.h b/cpu/stm32/include/periph_cpu.h index ac5f80c625..e862625bf6 100644 --- a/cpu/stm32/include/periph_cpu.h +++ b/cpu/stm32/include/periph_cpu.h @@ -72,6 +72,7 @@ #include "periph/cpu_timer.h" #include "periph/cpu_uart.h" #include "periph/cpu_usbdev.h" +#include "periph/cpu_vbat.h" #include "periph/cpu_wdt.h" #ifdef MODULE_PERIPH_CAN diff --git a/cpu/stm32/kconfigs/f0/Kconfig.lines b/cpu/stm32/kconfigs/f0/Kconfig.lines index 6a9d49432c..e52ba029c1 100644 --- a/cpu/stm32/kconfigs/f0/Kconfig.lines +++ b/cpu/stm32/kconfigs/f0/Kconfig.lines @@ -27,33 +27,39 @@ config CPU_LINE_STM32F031X6 bool select CPU_FAM_F0 select HAS_PERIPH_RTC_MEM + select HAS_PERIPH_VBAT config CPU_LINE_STM32F038XX bool select CPU_FAM_F0 select HAS_PERIPH_RTC_MEM + select HAS_PERIPH_VBAT config CPU_LINE_STM32F042X6 bool select CPU_FAM_F0 select HAS_PERIPH_RTC_MEM + select HAS_PERIPH_VBAT config CPU_LINE_STM32F048XX bool select CPU_FAM_F0 select HAS_PERIPH_RTC_MEM + select HAS_PERIPH_VBAT config CPU_LINE_STM32F051X8 bool select CPU_FAM_F0 select CLOCK_HAS_NO_MCO_PRE select HAS_PERIPH_RTC_MEM + select HAS_PERIPH_VBAT config CPU_LINE_STM32F058XX bool select CPU_FAM_F0 select CLOCK_HAS_NO_MCO_PRE select HAS_PERIPH_RTC_MEM + select HAS_PERIPH_VBAT config CPU_LINE_STM32F070X6 bool @@ -67,23 +73,28 @@ config CPU_LINE_STM32F071XB bool select CPU_FAM_F0 select HAS_PERIPH_RTC_MEM + select HAS_PERIPH_VBAT config CPU_LINE_STM32F072XB bool select CPU_FAM_F0 select HAS_PERIPH_RTC_MEM + select HAS_PERIPH_VBAT config CPU_LINE_STM32F078XX bool select CPU_FAM_F0 select HAS_PERIPH_RTC_MEM + select HAS_PERIPH_VBAT config CPU_LINE_STM32F091XC bool select CPU_FAM_F0 select HAS_PERIPH_RTC_MEM + select HAS_PERIPH_VBAT config CPU_LINE_STM32F098XX bool select CPU_FAM_F0 select HAS_PERIPH_RTC_MEM + select HAS_PERIPH_VBAT diff --git a/cpu/stm32/kconfigs/f2/Kconfig b/cpu/stm32/kconfigs/f2/Kconfig index d43df8d421..00a08c8fd0 100644 --- a/cpu/stm32/kconfigs/f2/Kconfig +++ b/cpu/stm32/kconfigs/f2/Kconfig @@ -15,6 +15,7 @@ config CPU_FAM_F2 select HAS_PERIPH_FLASHPAGE select HAS_PERIPH_HWRNG select HAS_PERIPH_RTC_MEM + select HAS_PERIPH_VBAT select HAS_PERIPH_WDT select HAS_BOOTLOADER_STM32 diff --git a/cpu/stm32/kconfigs/f3/Kconfig b/cpu/stm32/kconfigs/f3/Kconfig index 93651422b5..2cd5983079 100644 --- a/cpu/stm32/kconfigs/f3/Kconfig +++ b/cpu/stm32/kconfigs/f3/Kconfig @@ -14,6 +14,7 @@ config CPU_FAM_F3 select HAS_PERIPH_FLASHPAGE_PAGEWISE select HAS_PERIPH_FLASHPAGE_RAW select HAS_PERIPH_RTC_MEM + select HAS_PERIPH_VBAT select HAS_PERIPH_WDT select HAS_BOOTLOADER_STM32 diff --git a/cpu/stm32/kconfigs/f4/Kconfig b/cpu/stm32/kconfigs/f4/Kconfig index 0d510fc4be..889bebdb62 100644 --- a/cpu/stm32/kconfigs/f4/Kconfig +++ b/cpu/stm32/kconfigs/f4/Kconfig @@ -13,6 +13,7 @@ config CPU_FAM_F4 select HAS_CORTEXM_MPU select HAS_PERIPH_FLASHPAGE select HAS_PERIPH_RTC_MEM + select HAS_PERIPH_VBAT select HAS_PERIPH_WDT select HAS_BOOTLOADER_STM32 diff --git a/cpu/stm32/kconfigs/f7/Kconfig b/cpu/stm32/kconfigs/f7/Kconfig index 9647a952c8..4e3e0187d0 100644 --- a/cpu/stm32/kconfigs/f7/Kconfig +++ b/cpu/stm32/kconfigs/f7/Kconfig @@ -15,6 +15,7 @@ config CPU_FAM_F7 select HAS_PERIPH_FLASHPAGE select HAS_PERIPH_HWRNG select HAS_PERIPH_RTC_MEM + select HAS_PERIPH_VBAT select HAS_PERIPH_WDT select HAS_BOOTLOADER_STM32 diff --git a/cpu/stm32/kconfigs/g0/Kconfig b/cpu/stm32/kconfigs/g0/Kconfig index b1157ce533..891b429c8b 100644 --- a/cpu/stm32/kconfigs/g0/Kconfig +++ b/cpu/stm32/kconfigs/g0/Kconfig @@ -13,6 +13,7 @@ config CPU_FAM_G0 select HAS_PERIPH_FLASHPAGE select HAS_PERIPH_FLASHPAGE_PAGEWISE select HAS_PERIPH_FLASHPAGE_RAW + select HAS_PERIPH_VBAT select HAS_PERIPH_WDT select HAS_BOOTLOADER_STM32 diff --git a/cpu/stm32/kconfigs/g4/Kconfig b/cpu/stm32/kconfigs/g4/Kconfig index f80a6f9746..89e85d8c94 100644 --- a/cpu/stm32/kconfigs/g4/Kconfig +++ b/cpu/stm32/kconfigs/g4/Kconfig @@ -14,6 +14,7 @@ config CPU_FAM_G4 select HAS_PERIPH_FLASHPAGE select HAS_PERIPH_FLASHPAGE_PAGEWISE select HAS_PERIPH_HWRNG + select HAS_PERIPH_VBAT select HAS_PERIPH_WDT select HAS_BOOTLOADER_STM32 diff --git a/cpu/stm32/kconfigs/l4/Kconfig b/cpu/stm32/kconfigs/l4/Kconfig index 6ccd9df6af..d4fa612f40 100644 --- a/cpu/stm32/kconfigs/l4/Kconfig +++ b/cpu/stm32/kconfigs/l4/Kconfig @@ -15,6 +15,7 @@ config CPU_FAM_L4 select HAS_PERIPH_FLASHPAGE_PAGEWISE select HAS_PERIPH_HWRNG select HAS_PERIPH_RTC_MEM + select HAS_PERIPH_VBAT select HAS_PERIPH_WDT select HAS_BOOTLOADER_STM32 diff --git a/cpu/stm32/kconfigs/l5/Kconfig b/cpu/stm32/kconfigs/l5/Kconfig index 46d5f24857..5a227b62ac 100644 --- a/cpu/stm32/kconfigs/l5/Kconfig +++ b/cpu/stm32/kconfigs/l5/Kconfig @@ -14,6 +14,7 @@ config CPU_FAM_L5 select HAS_PERIPH_FLASHPAGE_PAGEWISE select HAS_PERIPH_HWRNG select HAS_PERIPH_RTC_MEM + select HAS_PERIPH_VBAT select HAS_PERIPH_WDT select HAS_BOOTLOADER_STM32 diff --git a/cpu/stm32/kconfigs/u5/Kconfig b/cpu/stm32/kconfigs/u5/Kconfig index 6129b2ce08..7304394a98 100644 --- a/cpu/stm32/kconfigs/u5/Kconfig +++ b/cpu/stm32/kconfigs/u5/Kconfig @@ -15,6 +15,7 @@ config CPU_FAM_U5 select HAS_PERIPH_FLASHPAGE_PAGEWISE select HAS_PERIPH_HWRNG select HAS_PERIPH_RTC_MEM + select HAS_PERIPH_VBAT select HAS_PERIPH_WDT select HAS_BOOTLOADER_STM32 diff --git a/cpu/stm32/kconfigs/wb/Kconfig b/cpu/stm32/kconfigs/wb/Kconfig index 61f2f7444e..c49cc9b9dc 100644 --- a/cpu/stm32/kconfigs/wb/Kconfig +++ b/cpu/stm32/kconfigs/wb/Kconfig @@ -14,6 +14,7 @@ config CPU_FAM_WB select HAS_PERIPH_FLASHPAGE_PAGEWISE select HAS_PERIPH_HWRNG select HAS_PERIPH_RTC_MEM + select HAS_PERIPH_VBAT select HAS_PERIPH_WDT select HAS_BOOTLOADER_STM32 diff --git a/cpu/stm32/kconfigs/wl/Kconfig b/cpu/stm32/kconfigs/wl/Kconfig index 7df178c438..a887221b6a 100644 --- a/cpu/stm32/kconfigs/wl/Kconfig +++ b/cpu/stm32/kconfigs/wl/Kconfig @@ -14,6 +14,7 @@ config CPU_FAM_WL select HAS_PERIPH_FLASHPAGE select HAS_PERIPH_FLASHPAGE_PAGEWISE select HAS_PERIPH_RTC_MEM + select HAS_PERIPH_VBAT select HAS_PERIPH_WDT select HAS_BOOTLOADER_STM32 diff --git a/cpu/stm32/periph/adc_f0_g0.c b/cpu/stm32/periph/adc_f0_g0.c index 50f68fffd9..2c1933784c 100644 --- a/cpu/stm32/periph/adc_f0_g0.c +++ b/cpu/stm32/periph/adc_f0_g0.c @@ -22,6 +22,14 @@ #include "cpu.h" #include "mutex.h" #include "periph/adc.h" +#include "periph/vbat.h" + +/** + * @brief Default VBAT undefined value + */ +#ifndef VBAT_ADC +#define VBAT_ADC ADC_UNDEF +#endif /** * @brief Allocate lock for the ADC device @@ -62,7 +70,9 @@ int adc_init(adc_t line) /* lock and power on the device */ prep(); /* configure the pin */ - gpio_init_analog(adc_config[line].pin); + if (adc_config[line].pin != GPIO_UNDEF) { + gpio_init_analog(adc_config[line].pin); + } /* reset configuration */ ADC1->CFGR2 = 0; /* enable device */ @@ -86,7 +96,10 @@ int32_t adc_sample(adc_t line, adc_res_t res) /* lock and power on the ADC device */ prep(); - + /* check if this is the VBAT line */ + if (IS_USED(MODULE_PERIPH_VBAT) && line == VBAT_ADC) { + vbat_enable(); + } /* set resolution and channel */ ADC1->CFGR1 = res; ADC1->CHSELR = (1 << adc_config[line].chan); @@ -95,7 +108,10 @@ int32_t adc_sample(adc_t line, adc_res_t res) while (!(ADC1->ISR & ADC_ISR_EOC)) {} /* read result */ sample = (int)ADC1->DR; - + /* check if this is the VBAT line */ + if (IS_USED(MODULE_PERIPH_VBAT) && line == VBAT_ADC) { + vbat_disable(); + } /* unlock and power off device again */ done(); diff --git a/cpu/stm32/periph/adc_f2.c b/cpu/stm32/periph/adc_f2.c index 3136e5ee6e..b6c7acaf96 100644 --- a/cpu/stm32/periph/adc_f2.c +++ b/cpu/stm32/periph/adc_f2.c @@ -24,12 +24,20 @@ #include "mutex.h" #include "periph/adc.h" #include "periph_conf.h" +#include "periph/vbat.h" /** * @brief Maximum allowed ADC clock speed */ #define MAX_ADC_SPEED (12000000U) +/** + * @brief Default VBAT undefined value + */ +#ifndef VBAT_ADC +#define VBAT_ADC ADC_UNDEF +#endif + /** * @brief Allocate locks for all three available ADC devices */ @@ -73,7 +81,9 @@ int adc_init(adc_t line) prep(line); /* configure the pin */ - gpio_init_analog(adc_config[line].pin); + if (adc_config[line].pin != GPIO_UNDEF) { + gpio_init_analog(adc_config[line].pin); + } /* set clock prescaler to get the maximal possible ADC clock value */ for (clk_div = 2; clk_div < 8; clk_div += 2) { if ((CLOCK_CORECLOCK / clk_div) <= MAX_ADC_SPEED) { @@ -85,17 +95,6 @@ int adc_init(adc_t line) /* enable the ADC module */ dev(line)->CR2 = ADC_CR2_ADON; - /* check if this channel is an internal ADC channel, if so - * enable the internal temperature and Vref */ - if (adc_config[line].chan == 16 || adc_config[line].chan == 17) { - /* check if the internal channels are configured to use ADC1 */ - if (dev(line) != ADC1) { - return -3; - } - - ADC->CCR |= ADC_CCR_TSVREFE; - } - /* free the device again */ done(line); return 0; @@ -112,7 +111,15 @@ int32_t adc_sample(adc_t line, adc_res_t res) /* lock and power on the ADC device */ prep(line); - + /* check if this is the VBAT line or another internal ADC channel */ + if (IS_USED(MODULE_PERIPH_VBAT) && line == VBAT_ADC) { + vbat_enable(); + } + else if (dev(line) == ADC1) { + if (adc_config[line].chan == 16 || adc_config[line].chan == 17) { + ADC->CCR |= ADC_CCR_TSVREFE; + } + } /* set resolution and conversion channel */ dev(line)->CR1 = res; dev(line)->SQR3 = adc_config[line].chan; @@ -121,7 +128,15 @@ int32_t adc_sample(adc_t line, adc_res_t res) while (!(dev(line)->SR & ADC_SR_EOC)) {} /* finally read sample and reset the STRT bit in the status register */ sample = (int)dev(line)->DR; - + /* check if this is the VBAT line or another internal ADC channel */ + if (IS_USED(MODULE_PERIPH_VBAT) && line == VBAT_ADC) { + vbat_disable(); + } + else if (dev(line) == ADC1) { + if (adc_config[line].chan == 16 || adc_config[line].chan == 17) { + ADC->CCR &= ~ADC_CCR_TSVREFE; + } + } /* power off and unlock device again */ done(line); diff --git a/cpu/stm32/periph/adc_f3.c b/cpu/stm32/periph/adc_f3.c index 2f0603719c..dc022524ba 100644 --- a/cpu/stm32/periph/adc_f3.c +++ b/cpu/stm32/periph/adc_f3.c @@ -24,6 +24,7 @@ #include "periph/adc.h" #include "periph_conf.h" #include "ztimer.h" +#include "periph/vbat.h" #define SMP_MIN (0x2) /*< Sampling time for slow channels (0x2 = 4.5 ADC clock cycles) */ @@ -33,6 +34,13 @@ #define ADC_INSTANCE ADC12_COMMON #endif +/** + * @brief Default VBAT undefined value + */ +#ifndef VBAT_ADC +#define VBAT_ADC ADC_UNDEF +#endif + /** * @brief Allocate locks for all available ADC devices */ @@ -128,8 +136,9 @@ int adc_init(adc_t line) } /* Configure the pin */ - gpio_init_analog(adc_config[line].pin); - + if (adc_config[line].pin != GPIO_UNDEF) { + gpio_init_analog(adc_config[line].pin); + } /* Init ADC line only if it wasn't already initialized */ if (!(dev(line)->CR & ADC_CR_ADEN)) { /* Enable ADC internal voltage regulator and wait for startup period */ @@ -192,6 +201,11 @@ int32_t adc_sample(adc_t line, adc_res_t res) /* Lock and power on the ADC device */ prep(line); + /* check if this is the VBAT line */ + if (IS_USED(MODULE_PERIPH_VBAT) && line == VBAT_ADC) { + vbat_enable(); + } + /* Set resolution */ dev(line)->CFGR &= ~ADC_CFGR_RES; dev(line)->CFGR |= res; @@ -206,6 +220,11 @@ int32_t adc_sample(adc_t line, adc_res_t res) /* Read the sample */ sample = (int)dev(line)->DR; + /* check if this is the VBAT line */ + if (IS_USED(MODULE_PERIPH_VBAT) && line == VBAT_ADC) { + vbat_disable(); + } + /* Power off and unlock device again */ done(line); diff --git a/cpu/stm32/periph/adc_f4_f7.c b/cpu/stm32/periph/adc_f4_f7.c index 378cb26144..64c489a6b1 100644 --- a/cpu/stm32/periph/adc_f4_f7.c +++ b/cpu/stm32/periph/adc_f4_f7.c @@ -23,12 +23,20 @@ #include "mutex.h" #include "periph/adc.h" #include "periph_conf.h" +#include "periph/vbat.h" /** * @brief Maximum allowed ADC clock speed */ #define MAX_ADC_SPEED (12000000U) +/** + * @brief Default VBAT undefined value + */ +#ifndef VBAT_ADC +#define VBAT_ADC ADC_UNDEF +#endif + /** * @brief Allocate locks for all three available ADC devices */ @@ -72,7 +80,9 @@ int adc_init(adc_t line) prep(line); /* configure the pin */ - gpio_init_analog(adc_config[line].pin); + if (adc_config[line].pin != GPIO_UNDEF) { + gpio_init_analog(adc_config[line].pin); + } /* set sequence length to 1 conversion and enable the ADC device */ dev(line)->SQR1 = 0; dev(line)->CR2 = ADC_CR2_ADON; @@ -100,7 +110,10 @@ int32_t adc_sample(adc_t line, adc_res_t res) /* lock and power on the ADC device */ prep(line); - + /* check if this channel is an internal ADC channel */ + if (IS_USED(MODULE_PERIPH_VBAT) && line == VBAT_ADC) { + vbat_enable(); + } /* set resolution and conversion channel */ dev(line)->CR1 = res; dev(line)->SQR3 = adc_config[line].chan; @@ -109,7 +122,10 @@ int32_t adc_sample(adc_t line, adc_res_t res) while (!(dev(line)->SR & ADC_SR_EOC)) {} /* finally read sample and reset the STRT bit in the status register */ sample = (int)dev(line)->DR; - + /* check if this channel was an internal ADC channel */ + if (IS_USED(MODULE_PERIPH_VBAT) && line == VBAT_ADC) { + vbat_disable(); + } /* power off and unlock device again */ done(line); diff --git a/cpu/stm32/periph/adc_l4.c b/cpu/stm32/periph/adc_l4.c index 6dc7df9bf8..7c2c7e13bd 100644 --- a/cpu/stm32/periph/adc_l4.c +++ b/cpu/stm32/periph/adc_l4.c @@ -25,6 +25,7 @@ #include "mutex.h" #include "periph/adc.h" #include "periph_conf.h" +#include "periph/vbat.h" #include "ztimer.h" /** @@ -55,6 +56,13 @@ #define ADC_SMPR2_FIRST_CHAN (10) #endif +/** + * @brief Default VBAT undefined value + */ +#ifndef VBAT_ADC +#define VBAT_ADC ADC_UNDEF +#endif + /** * @brief Allocate locks for all three available ADC devices */ @@ -122,8 +130,9 @@ int adc_init(adc_t line) } /* configure the pin */ - gpio_init_analog(adc_config[line].pin); - + if (adc_config[line].pin != GPIO_UNDEF) { + gpio_init_analog(adc_config[line].pin); + } #if defined(CPU_MODEL_STM32L476RG) || defined(CPU_MODEL_STM32L475VG) /* On STM32L475xx/476xx/486xx devices, before any conversion of an input channel coming from GPIO pads, it is necessary to configure the corresponding GPIOx_ASCR register in @@ -192,6 +201,11 @@ int32_t adc_sample(adc_t line, adc_res_t res) /* lock and power on the ADC device */ prep(line); + /* check if this is the VBAT line */ + if (IS_USED(MODULE_PERIPH_VBAT) && line == VBAT_ADC) { + vbat_enable(); + } + /* first clear resolution */ dev(line)->CFGR &= ~(ADC_CFGR_RES); @@ -208,6 +222,11 @@ int32_t adc_sample(adc_t line, adc_res_t res) /* read the sample */ sample = (int)dev(line)->DR; + /* check if this is the VBAT line */ + if (IS_USED(MODULE_PERIPH_VBAT) && line == VBAT_ADC) { + vbat_disable(); + } + /* free the device again */ done(line); diff --git a/cpu/stm32/periph/adc_wl.c b/cpu/stm32/periph/adc_wl.c index f3ccb2b7b4..7a895d613e 100644 --- a/cpu/stm32/periph/adc_wl.c +++ b/cpu/stm32/periph/adc_wl.c @@ -27,8 +27,16 @@ #include "mutex.h" #include "periph/adc.h" #include "periph_conf.h" +#include "periph/vbat.h" #include "ztimer.h" +/** + * @brief Default VBAT undefined value + */ +#ifndef VBAT_ADC +#define VBAT_ADC ADC_UNDEF +#endif + /** * @brief Allocate lock for the ADC device * @@ -59,7 +67,9 @@ int adc_init(adc_t line) prep(); /* configure the pin */ - gpio_init_analog(adc_config[line].pin); + if (adc_config[line].pin != GPIO_UNDEF) { + gpio_init_analog(adc_config[line].pin); + } /* init ADC line only if it wasn't already initialized */ if (!(ADC->CR & (ADC_CR_ADEN))) { @@ -116,6 +126,11 @@ int32_t adc_sample(adc_t line, adc_res_t res) /* lock and power on the ADC device */ prep(); + /* check if this is the VBAT line */ + if (IS_USED(MODULE_PERIPH_VBAT) && line == VBAT_ADC) { + vbat_enable(); + } + /* first clear resolution */ ADC->CFGR1 &= ~ADC_CFGR1_RES; @@ -132,6 +147,11 @@ int32_t adc_sample(adc_t line, adc_res_t res) /* read the sample */ sample = (int)ADC->DR; + /* check if this is the VBAT line */ + if (IS_USED(MODULE_PERIPH_VBAT) && line == VBAT_ADC) { + vbat_disable(); + } + /* free the device again */ done(); diff --git a/cpu/stm32/periph/vbat.c b/cpu/stm32/periph/vbat.c new file mode 100644 index 0000000000..71028727e7 --- /dev/null +++ b/cpu/stm32/periph/vbat.c @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2022 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_stm32 + * @ingroup drivers_periph_vbat + * @{ + * + * @file + * @brief Implementation of STM32 backup battery monitoring + * + * @author Fabian Hüßler + * @} + */ + +#include "board.h" +#include "periph_conf.h" +#include "periph/adc.h" +#include "periph/vbat.h" + +/** + * @name Constants depending on CPU line + * @{ + * + * @ref VBAT_ADC_SCALE is a scale factor to calculate the right voltage value + * as documented in the data sheet. + * @ref VBAT_ADC_MIN_MV <= VBAT[mV] is the smallest voltage level required + * to power the backup domain. + */ +/* f0 */ +#if defined(CPU_LINE_STM32F031x6) || defined(CPU_LINE_STM32F038xx) || \ + defined(CPU_LINE_STM32F042x6) || defined(CPU_LINE_STM32F048xx) || \ + defined(CPU_LINE_STM32F051x8) || defined(CPU_LINE_STM32F058xx) || \ + defined(CPU_LINE_STM32F071xB) || defined(CPU_LINE_STM32F072xB) || \ + defined(CPU_LINE_STM32F078xx) || defined(CPU_LINE_STM32F091xC) || \ + defined(CPU_LINE_STM32F098xx) +#define VBAT_ADC_SCALE 2 +#define VBAT_ADC_MIN_MV 1650 +/* f2 */ +#elif defined(CPU_LINE_STM32F205xx) || defined(CPU_LINE_STM32F207xx) || \ + defined(CPU_LINE_STM32F215xx) || defined(CPU_LINE_STM32F217xx) +#define VBAT_ADC_SCALE 2 +#define VBAT_ADC_MIN_MV 1800 +/* f3 */ +#elif defined(CPU_LINE_STM32F301x8) || defined(CPU_LINE_STM32F302x8) || \ + defined(CPU_LINE_STM32F302xC) || defined(CPU_LINE_STM32F302xE) || \ + defined(CPU_LINE_STM32F303x8) || defined(CPU_LINE_STM32F303xC) || \ + defined(CPU_LINE_STM32F303xE) || defined(CPU_LINE_STM32F318x8) || \ + defined(CPU_LINE_STM32F318xx) || defined(CPU_LINE_STM32F328xx) || \ + defined(CPU_LINE_STM32F334x8) || defined(CPU_LINE_STM32F358xx) || \ + defined(CPU_LINE_STM32F373xC) || defined(CPU_LINE_STM32F378xx) || \ + defined(CPU_LINE_STM32F398xx) +#define VBAT_ADC_SCALE 2 +#define VBAT_ADC_MIN_MV 1650 +/* f4 */ +#elif defined(CPU_LINE_STM32F401xC) || defined(CPU_LINE_STM32F401xE) || \ + defined(CPU_LINE_STM32F410Cx) || defined(CPU_LINE_STM32F410Rx) || \ + defined(CPU_LINE_STM32F410Tx) || defined(CPU_LINE_STM32F411xE) || \ + defined(CPU_LINE_STM32F412Cx) || defined(CPU_LINE_STM32F412Rx) || \ + defined(CPU_LINE_STM32F412Vx) || defined(CPU_LINE_STM32F412Zx) || \ + defined(CPU_LINE_STM32F413xx) || defined(CPU_LINE_STM32F423xx) || \ + defined(CPU_LINE_STM32F427xx) || defined(CPU_LINE_STM32F429xx) || \ + defined(CPU_LINE_STM32F437xx) || defined(CPU_LINE_STM32F439xx) || \ + defined(CPU_LINE_STM32F446xx) || defined(CPU_LINE_STM32F469xx) || \ + defined(CPU_LINE_STM32F479xx) +#define VBAT_ADC_SCALE 4 +#define VBAT_ADC_MIN_MV 1650 +#elif defined(CPU_LINE_STM32F405xx) || defined(CPU_LINE_STM32F407xx) || \ + defined(CPU_LINE_STM32F415xx) || defined(CPU_LINE_STM32F417xx) +#define VBAT_ADC_SCALE 2 +#define VBAT_ADC_MIN_MV 1650 +/* f7 */ +#elif defined(CPU_LINE_STM32F722xx) || defined(CPU_LINE_STM32F723xx) || \ + defined(CPU_LINE_STM32F730xx) || defined(CPU_LINE_STM32F732xx) || \ + defined(CPU_LINE_STM32F733xx) || defined(CPU_LINE_STM32F745xx) || \ + defined(CPU_LINE_STM32F746xx) || defined(CPU_LINE_STM32F750xx) || \ + defined(CPU_LINE_STM32F756xx) || defined(CPU_LINE_STM32F765xx) || \ + defined(CPU_LINE_STM32F767xx) || defined(CPU_LINE_STM32F769xx) || \ + defined(CPU_LINE_STM32F777xx) || defined(CPU_LINE_STM32F779xx) +#define VBAT_ADC_SCALE 4 +#define VBAT_ADC_MIN_MV 1650 +/* g0 */ +#elif defined(CPU_LINE_STM32G030xx) || defined(CPU_LINE_STM32G031xx) || \ + defined(CPU_LINE_STM32G041xx) || defined(CPU_LINE_STM32G050xx) || \ + defined(CPU_LINE_STM32G051xx) || defined(CPU_LINE_STM32G061xx) || \ + defined(CPU_LINE_STM32G070xx) || defined(CPU_LINE_STM32G071xx) || \ + defined(CPU_LINE_STM32G081xx) || defined(CPU_LINE_STM32G0B0xx) || \ + defined(CPU_LINE_STM32G0B1xx) || defined(CPU_LINE_STM32G0C1xx) +#define VBAT_ADC_SCALE 3 +#define VBAT_ADC_MIN_MV 1550 +/* g4 */ +#elif defined(CPU_LINE_STM32G431xx) || defined(CPU_LINE_STM32G441xx) || \ + defined(CPU_LINE_STM32G471xx) || defined(CPU_LINE_STM32G473xx) || \ + defined(CPU_LINE_STM32G474xx) || defined(CPU_LINE_STM32G483xx) || \ + defined(CPU_LINE_STM32G484xx) || defined(CPU_LINE_STM32G491xx) || \ + defined(CPU_LINE_STM32G4A1xx) || defined(CPU_LINE_STM32G441xx) || \ + defined(CPU_LINE_STM32GBK1CB) +#define VBAT_ADC_SCALE 3 +#define VBAT_ADC_MIN_MV 1550 +/* l4 */ +#elif defined(CPU_LINE_STM32L412xx) || defined(CPU_LINE_STM32L422xx) || \ + defined(CPU_LINE_STM32L431xx) || defined(CPU_LINE_STM32L432xx) || \ + defined(CPU_LINE_STM32L433xx) || defined(CPU_LINE_STM32L442xx) || \ + defined(CPU_LINE_STM32L443xx) || defined(CPU_LINE_STM32L451xx) || \ + defined(CPU_LINE_STM32L452xx) || defined(CPU_LINE_STM32L462xx) || \ + defined(CPU_LINE_STM32L471xx) || defined(CPU_LINE_STM32L475xx) || \ + defined(CPU_LINE_STM32L476xx) || defined(CPU_LINE_STM32L485xx) || \ + defined(CPU_LINE_STM32L486xx) || defined(CPU_LINE_STM32L496xx) || \ + defined(CPU_LINE_STM32L4A6xx) || defined(CPU_LINE_STM32L4P5xx) || \ + defined(CPU_LINE_STM32L4Q5xx) || defined(CPU_LINE_STM32L4R5xx) || \ + defined(CPU_LINE_STM32L4R7xx) || defined(CPU_LINE_STM32L4R9xx) || \ + defined(CPU_LINE_STM32L4S5xx) || defined(CPU_LINE_STM32L4S7xx) || \ + defined(CPU_LINE_STM32L4S9xx) +#define VBAT_ADC_SCALE 3 +#define VBAT_ADC_MIN_MV 1550 +/* l5 */ +#elif defined(CPU_LINE_STM32L552xx) || defined(CPU_LINE_STM32L562xx) +#define VBAT_ADC_SCALE 3 +#define VBAT_ADC_MIN_MV 1550 +/* u5 */ +#elif defined(CPU_LINE_STM32U575xx) || defined(CPU_LINE_STM32U585xx) +#define VBAT_ADC_SCALE 4 +#define VBAT_ADC_MIN_MV 1650 +/* wb */ +#elif defined(CPU_LINE_STM32WB10xx) || defined(CPU_LINE_STM32WB15xx) || \ + defined(CPU_LINE_STM32WB30xx) || defined(CPU_LINE_STM32WB35xx) || \ + defined(CPU_LINE_STM32WB50xx) || defined(CPU_LINE_STM32WB55xx) || \ + defined(CPU_LINE_STM32WB5Mxx) +#define VBAT_ADC_SCALE 3 +#define VBAT_ADC_MIN_MV 1550 +/* wl */ +#elif defined(CPU_LINE_STM32WL54xx) || defined(CPU_LINE_STM32WL55xx) || \ + defined(CPU_LINE_STM32WLE4xx) || defined(CPU_LINE_STM32WLE5xx) +#define VBAT_ADC_SCALE 3 +#define VBAT_ADC_MIN_MV 1550 +#else +#error "VBAT: CPU line is not supported so far." +#endif +/** @} */ + +/** + * @name VBAT enable register + * @{ + */ +#if defined(CPU_LINE_STM32F373xC) || defined(CPU_LINE_STM32F378xx) +#define ADC_CCR_REG (SYSCFG->CFGR1) /* ADCx_COMMON is also defined */ +#elif defined(ADC_COMMON) +#define ADC_CCR_REG (ADC_COMMON->CCR) +#elif defined(ADC1_COMMON) +#define ADC_CCR_REG (ADC1_COMMON->CCR) +#elif defined(ADC12_COMMON) +#define ADC_CCR_REG (ADC12_COMMON->CCR) +#elif defined(ADC123_COMMON) +#define ADC_CCR_REG (ADC123_COMMON->CCR) +#elif defined(ADC12_COMMON_NS) +#define ADC_CCR_REG (ADC12_COMMON_NS->CCR) +#elif defined(ADC) +#define ADC_CCR_REG (ADC->CCR) +#else +#error "VBAT: CPU line is not supported so far." +#endif +/** @} */ + +/** + * @name VBAT enable flag + * @{ + */ +#if defined(ADC_CCR_VBATEN) +#define VBAT_ENABLE ADC_CCR_VBATEN; +#elif defined(ADC_CCR_VBATE) +#define VBAT_ENABLE ADC_CCR_VBATE; +#elif defined(ADC_CCR_VBATSEL) +#define VBAT_ENABLE ADC_CCR_VBATSEL; +#elif defined(SYSCFG_CFGR1_VBAT) +#define VBAT_ENABLE SYSCFG_CFGR1_VBAT; +#else +#error "VBAT: CPU line is not supported so far." +#endif +/** @} */ + +#ifndef CONFIG_VBAT_ADC_VREF_MV +#define CONFIG_VBAT_ADC_VREF_MV 3300 /**< ADC reference voltage */ +#endif + +/** + * @brief Override this function if you know how to retrieve the accurate + * ADC supply voltage in mV for your board. The default behaviour is + * to return @ref CONFIG_VBAT_ADC_VREF_MV. + * Once there is a driver to sample VREFINT, this function is likely + * to be changed. + */ +int32_t __attribute__((weak)) vref_mv(void) { + return CONFIG_VBAT_ADC_VREF_MV; +} + +#ifndef VBAT_ADC +#error "VBAT: Add internal VBAT ADC line to adc_config[] and #define VBAT_ADC." +#endif + +int vbat_init(void) +{ + return adc_init(VBAT_ADC); +} + +void vbat_enable(void) +{ + ADC_CCR_REG |= VBAT_ENABLE; +} + +void vbat_disable(void) +{ + ADC_CCR_REG &= ~VBAT_ENABLE; +} + +int32_t vbat_sample_mv(void) +{ + int32_t mv = adc_sample(VBAT_ADC, VBAT_ADC_RES); + mv = (mv * VBAT_ADC_SCALE * vref_mv()) / VBAT_ADC_MAX; + return mv; +} + +bool vbat_is_empty(void) +{ + return VBAT_ADC_MIN_MV > vbat_sample_mv(); +} diff --git a/drivers/periph_common/Kconfig b/drivers/periph_common/Kconfig index 2947f5c5b0..14219ec373 100644 --- a/drivers/periph_common/Kconfig +++ b/drivers/periph_common/Kconfig @@ -170,4 +170,5 @@ config HAVE_SHARED_PERIPH_RTT_PERIPH_RTC only one can be selected. rsource "Kconfig.timer" +rsource "Kconfig.vbat" rsource "Kconfig.wdt" diff --git a/drivers/periph_common/Kconfig.vbat b/drivers/periph_common/Kconfig.vbat new file mode 100644 index 0000000000..0df040285a --- /dev/null +++ b/drivers/periph_common/Kconfig.vbat @@ -0,0 +1,39 @@ +# Copyright (c) 2022 Otto-von-Guericke-Universität Magdeburg +# +# This file is subject to the terms and conditions of the GNU Lesser +# General Public License v2.1. See the file LICENSE in the top level +# directory for more details. +# + +menuconfig MODULE_PERIPH_VBAT + bool "Backup Battery monitoring driver" + depends on HAS_PERIPH_VBAT + depends on HAS_PERIPH_ADC + depends on TEST_KCONFIG + select MODULE_PERIPH_ADC + +if MODULE_PERIPH_VBAT + +config MODULE_PERIPH_INIT_VBAT + bool "Auto initialize VBAT ADC line" + default y if MODULE_PERIPH_INIT + +config VBAT_ADC_VREF_MV + int "ADC reference voltage in mV" + default 3300 + +endif # MODULE_PERIPH_VBAT + +menuconfig KCONFIG_USEMODULE_PERIPH_VBAT + bool "Configure backup battery monitoring peripheral driver" + depends on USEMODULE_PERIPH_VBAT + help + Configure backup battery monitoring peripheral driver using Kconfig. + +config VBAT_ADC_VREF_MV + int "ADC reference voltage in mV" + default 3300 + depends on KCONFIG_USEMODULE_PERIPH_VBAT + help + This is the reference voltage (VREF) of the ADC. + Often VREF is connected with VDDA, which is equal to VDD. diff --git a/kconfigs/Kconfig.features b/kconfigs/Kconfig.features index 5469b2420b..c178989a29 100644 --- a/kconfigs/Kconfig.features +++ b/kconfigs/Kconfig.features @@ -369,6 +369,11 @@ config HAS_PERIPH_USBDEV help Indicates that an USBDEV peripheral is present. +config HAS_PERIPH_VBAT + bool + help + Indicates that backup battery monitoring is supported + config HAS_PERIPH_WDT bool help From 9163d78910984aa6ba4bc27e18af9b6a835424c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20H=C3=BC=C3=9Fler?= Date: Thu, 7 Oct 2021 21:19:04 +0200 Subject: [PATCH 3/6] boards: add VBAT for stm32 based boards with ADC --- boards/common/weact-f4x1cx/include/periph_conf.h | 2 ++ boards/lora-e5-dev/include/periph_conf.h | 2 ++ boards/msbiot/include/periph_conf.h | 4 +++- boards/nucleo-f031k6/include/periph_conf.h | 4 +++- boards/nucleo-f042k6/include/periph_conf.h | 4 +++- boards/nucleo-f072rb/include/periph_conf.h | 4 +++- boards/nucleo-f091rc/include/periph_conf.h | 4 +++- boards/nucleo-f207zg/include/periph_conf.h | 4 +++- boards/nucleo-f302r8/include/periph_conf.h | 4 +++- boards/nucleo-f303k8/include/periph_conf.h | 4 +++- boards/nucleo-f303re/include/periph_conf.h | 4 +++- boards/nucleo-f303ze/include/periph_conf.h | 6 ++++-- boards/nucleo-f334r8/include/periph_conf.h | 4 +++- boards/nucleo-f401re/include/periph_conf.h | 4 +++- boards/nucleo-f410rb/include/periph_conf.h | 4 +++- boards/nucleo-f411re/include/periph_conf.h | 4 +++- boards/nucleo-f412zg/include/periph_conf.h | 4 +++- boards/nucleo-f413zh/include/periph_conf.h | 4 +++- boards/nucleo-f429zi/include/periph_conf.h | 4 +++- boards/nucleo-f446re/include/periph_conf.h | 4 +++- boards/nucleo-f767zi/include/periph_conf.h | 4 +++- boards/nucleo-g070rb/include/periph_conf.h | 4 +++- boards/nucleo-g071rb/include/periph_conf.h | 4 +++- boards/nucleo-l476rg/include/periph_conf.h | 3 +++ boards/stm32f0discovery/include/periph_conf.h | 4 +++- boards/stm32f469i-disco/include/periph_conf.h | 5 ++++- boards/stm32f4discovery/include/periph_conf.h | 4 +++- boards/ublox-c030-u201/include/periph_conf.h | 4 +++- 28 files changed, 84 insertions(+), 26 deletions(-) diff --git a/boards/common/weact-f4x1cx/include/periph_conf.h b/boards/common/weact-f4x1cx/include/periph_conf.h index 37537b72e0..7f10229e36 100644 --- a/boards/common/weact-f4x1cx/include/periph_conf.h +++ b/boards/common/weact-f4x1cx/include/periph_conf.h @@ -179,8 +179,10 @@ static const adc_conf_t adc_config[] = { {GPIO_PIN(PORT_A, 1), 0, 1}, {GPIO_PIN(PORT_A, 4), 0, 4}, {GPIO_PIN(PORT_B, 0), 0, 8}, + {GPIO_UNDEF, 0, 18} /* VBAT */ }; +#define VBAT_ADC ADC_LINE(4) /**< VBAT ADC line */ #define ADC_NUMOF ARRAY_SIZE(adc_config) /** @} */ diff --git a/boards/lora-e5-dev/include/periph_conf.h b/boards/lora-e5-dev/include/periph_conf.h index 8c7e6c94c8..4df678de62 100644 --- a/boards/lora-e5-dev/include/periph_conf.h +++ b/boards/lora-e5-dev/include/periph_conf.h @@ -160,8 +160,10 @@ static const i2c_conf_t i2c_config[] = { static const adc_conf_t adc_config[] = { { GPIO_PIN(PORT_B, 3), 2 }, { GPIO_PIN(PORT_B, 4), 3 }, + { GPIO_UNDEF, 14 }, /* VBAT */ }; +#define VBAT_ADC ADC_LINE(2) /**< VBAT ADC line */ #define ADC_NUMOF ARRAY_SIZE(adc_config) /** @} */ diff --git a/boards/msbiot/include/periph_conf.h b/boards/msbiot/include/periph_conf.h index 353d05ea72..5f3f016323 100644 --- a/boards/msbiot/include/periph_conf.h +++ b/boards/msbiot/include/periph_conf.h @@ -105,9 +105,11 @@ static const pwm_conf_t pwm_config[] = { */ static const adc_conf_t adc_config[] = { {GPIO_PIN(PORT_B, 0), 0, 8}, - {GPIO_PIN(PORT_B, 1), 0, 9} + {GPIO_PIN(PORT_B, 1), 0, 9}, + {GPIO_UNDEF, 0, 18}, /* VBAT */ }; +#define VBAT_ADC ADC_LINE(2) /**< VBAT ADC line */ #define ADC_NUMOF ARRAY_SIZE(adc_config) /** @} */ diff --git a/boards/nucleo-f031k6/include/periph_conf.h b/boards/nucleo-f031k6/include/periph_conf.h index 725157ffca..2ee35b7ce2 100644 --- a/boards/nucleo-f031k6/include/periph_conf.h +++ b/boards/nucleo-f031k6/include/periph_conf.h @@ -122,9 +122,11 @@ static const adc_conf_t adc_config[] = { { GPIO_PIN(PORT_A, 1), 1 }, { GPIO_PIN(PORT_A, 3), 3 }, { GPIO_PIN(PORT_A, 4), 4 }, - { GPIO_PIN(PORT_A, 7), 7 } + { GPIO_PIN(PORT_A, 7), 7 }, + { GPIO_UNDEF, 18 }, /* VBAT */ }; +#define VBAT_ADC ADC_LINE(5) /**< VBAT ADC line */ #define ADC_NUMOF ARRAY_SIZE(adc_config) /** @} */ diff --git a/boards/nucleo-f042k6/include/periph_conf.h b/boards/nucleo-f042k6/include/periph_conf.h index d63db22037..79853d068e 100644 --- a/boards/nucleo-f042k6/include/periph_conf.h +++ b/boards/nucleo-f042k6/include/periph_conf.h @@ -132,9 +132,11 @@ static const adc_conf_t adc_config[] = { { GPIO_PIN(PORT_A, 1), 1 }, { GPIO_PIN(PORT_A, 3), 3 }, { GPIO_PIN(PORT_A, 4), 4 }, - { GPIO_PIN(PORT_A, 7), 7 } + { GPIO_PIN(PORT_A, 7), 7 }, + { GPIO_UNDEF, 18 }, /* VBAT */ }; +#define VBAT_ADC ADC_LINE(5) /**< VBAT ADC line */ #define ADC_NUMOF ARRAY_SIZE(adc_config) /** @} */ diff --git a/boards/nucleo-f072rb/include/periph_conf.h b/boards/nucleo-f072rb/include/periph_conf.h index d4493d4f81..bd07bfb7cc 100644 --- a/boards/nucleo-f072rb/include/periph_conf.h +++ b/boards/nucleo-f072rb/include/periph_conf.h @@ -187,9 +187,11 @@ static const adc_conf_t adc_config[] = { { GPIO_PIN(PORT_A, 4), 4 }, { GPIO_PIN(PORT_B, 0), 8 }, { GPIO_PIN(PORT_C, 1), 11 }, - { GPIO_PIN(PORT_C, 0), 10 } + { GPIO_PIN(PORT_C, 0), 10 }, + { GPIO_UNDEF, 18 }, /* VBAT */ }; +#define VBAT_ADC ADC_LINE(6) /**< VBAT ADC line */ #define ADC_NUMOF ARRAY_SIZE(adc_config) /** @} */ diff --git a/boards/nucleo-f091rc/include/periph_conf.h b/boards/nucleo-f091rc/include/periph_conf.h index a922c54c18..c39216248a 100644 --- a/boards/nucleo-f091rc/include/periph_conf.h +++ b/boards/nucleo-f091rc/include/periph_conf.h @@ -196,9 +196,11 @@ static const adc_conf_t adc_config[] = { { GPIO_PIN(PORT_A, 4), 4 }, { GPIO_PIN(PORT_B, 0), 8 }, { GPIO_PIN(PORT_C, 1), 11 }, - { GPIO_PIN(PORT_C, 0), 10 } + { GPIO_PIN(PORT_C, 0), 10 }, + { GPIO_UNDEF, 18 }, /* VBAT */ }; +#define VBAT_ADC ADC_LINE(6) /**< VBAT ADC line */ #define ADC_NUMOF ARRAY_SIZE(adc_config) /** @} */ diff --git a/boards/nucleo-f207zg/include/periph_conf.h b/boards/nucleo-f207zg/include/periph_conf.h index 3ce29f9a07..764e5c7b5a 100644 --- a/boards/nucleo-f207zg/include/periph_conf.h +++ b/boards/nucleo-f207zg/include/periph_conf.h @@ -236,9 +236,11 @@ static const spi_conf_t spi_config[] = { */ static const adc_conf_t adc_config[] = { {GPIO_PIN(PORT_A, 3), 0, 3}, - {GPIO_PIN(PORT_C, 0), 1, 0} + {GPIO_PIN(PORT_C, 0), 1, 0}, + {GPIO_UNDEF, 0, 18}, /* VBAT */ }; +#define VBAT_ADC ADC_LINE(2) /**< VBAT ADC line */ #define ADC_NUMOF ARRAY_SIZE(adc_config) /** @} */ diff --git a/boards/nucleo-f302r8/include/periph_conf.h b/boards/nucleo-f302r8/include/periph_conf.h index bf674de8f5..f9c0592220 100644 --- a/boards/nucleo-f302r8/include/periph_conf.h +++ b/boards/nucleo-f302r8/include/periph_conf.h @@ -47,7 +47,7 @@ extern "C" { * Note that we do not configure all ADC channels, * and not in the STM32F302 order. Instead, we * just define 6 ADC channels, for the Nucleo - * Arduino header pins A0-A5 + * Arduino header pins A0-A5 and the internal VBAT channel. * * @{ */ @@ -58,8 +58,10 @@ static const adc_conf_t adc_config[] = { { .pin = GPIO_PIN(PORT_B, 0), .dev = 0, .chan = 11 }, /* ADC_IN11, slow */ { .pin = GPIO_PIN(PORT_C, 1), .dev = 0, .chan = 7 }, /* ADC_IN7, slow */ { .pin = GPIO_PIN(PORT_C, 0), .dev = 0, .chan = 6 }, /* ADC_IN6, slow */ + { .pin = GPIO_UNDEF, .dev = 0, .chan = 17 }, /* VBAT */ }; +#define VBAT_ADC ADC_LINE(6) /**< VBAT ADC line */ #define ADC_NUMOF ARRAY_SIZE(adc_config) /** @} */ diff --git a/boards/nucleo-f303k8/include/periph_conf.h b/boards/nucleo-f303k8/include/periph_conf.h index dc8eca27cd..70be4a9553 100644 --- a/boards/nucleo-f303k8/include/periph_conf.h +++ b/boards/nucleo-f303k8/include/periph_conf.h @@ -33,7 +33,7 @@ extern "C" { * Note that we do not configure all ADC channels, * and not in the STM32F303 order. Instead, we * just define 6 ADC channels, for the Nucleo - * Arduino header pins A0-A3 and A6 + * Arduino header pins A0-A3 and A6 and the internal VBAT channel. * * @{ */ @@ -43,8 +43,10 @@ static const adc_conf_t adc_config[] = { { .pin = GPIO_PIN(PORT_A, 3), .dev = 0, .chan = 4 }, /* ADC1_IN4, fast */ { .pin = GPIO_PIN(PORT_A, 4), .dev = 1, .chan = 1 }, /* ADC2_IN1, fast */ { .pin = GPIO_PIN(PORT_A, 7), .dev = 1, .chan = 4 }, /* ADC2_IN4, fast */ + { .pin = GPIO_UNDEF, .dev = 0, .chan = 17 }, /* VBAT */ }; +#define VBAT_ADC ADC_LINE(5) /**< VBAT ADC line */ #define ADC_NUMOF ARRAY_SIZE(adc_config) /** @} */ diff --git a/boards/nucleo-f303re/include/periph_conf.h b/boards/nucleo-f303re/include/periph_conf.h index 3a8c5e956d..d04f6b8542 100644 --- a/boards/nucleo-f303re/include/periph_conf.h +++ b/boards/nucleo-f303re/include/periph_conf.h @@ -45,7 +45,7 @@ extern "C" { * Note that we do not configure all ADC channels, * and not in the STM32F334 order. Instead, we * just define 6 ADC channels, for the Nucleo - * Arduino header pins A0-A5 + * Arduino header pins A0-A5 and the internal VBAT channel. * * @{ */ @@ -56,8 +56,10 @@ static const adc_conf_t adc_config[] = { { .pin = GPIO_PIN(PORT_B, 0), .dev = 2, .chan = 12 }, /* ADC3_IN12, slow */ { .pin = GPIO_PIN(PORT_C, 1), .dev = 1, .chan = 7 }, /* ADC12_IN7, slow */ { .pin = GPIO_PIN(PORT_C, 0), .dev = 1, .chan = 6 }, /* ADC12_IN6, slow */ + { .pin = GPIO_UNDEF, .dev = 0, .chan = 17 }, /* VBAT */ }; +#define VBAT_ADC ADC_LINE(6) /**< VBAT ADC line */ #define ADC_NUMOF ARRAY_SIZE(adc_config) /** @} */ diff --git a/boards/nucleo-f303ze/include/periph_conf.h b/boards/nucleo-f303ze/include/periph_conf.h index 1109a35248..fd5e0fc7aa 100644 --- a/boards/nucleo-f303ze/include/periph_conf.h +++ b/boards/nucleo-f303ze/include/periph_conf.h @@ -43,7 +43,7 @@ extern "C" { * Note that we do not configure all ADC channels, * and not in the STM32F303 order. Instead, we * just define 6 ADC channels, for the Nucleo - * Arduino header pins A0-A5 + * Arduino header pins A0-A5 and the internal VBAT channel. * * @{ */ @@ -53,9 +53,11 @@ static const adc_conf_t adc_config[] = { { .pin = GPIO_PIN(PORT_C, 3), .dev = 1, .chan = 9 }, /* ADC12_IN9, slow */ { .pin = GPIO_PIN(PORT_D, 11), .dev = 2, .chan = 8 }, /* ADC34_IN8, slow */ { .pin = GPIO_PIN(PORT_D, 12), .dev = 3, .chan = 9 }, /* ADC34_IN9, slow */ - { .pin = GPIO_PIN(PORT_D, 13), .dev = 3, .chan = 10 }, /* ADC34_IN10, slo */ + { .pin = GPIO_PIN(PORT_D, 13), .dev = 3, .chan = 10 }, /* ADC34_IN10, slow */ + { .pin = GPIO_UNDEF, .dev = 0, .chan = 17 }, /* VBAT */ }; +#define VBAT_ADC ADC_LINE(6) /**< VBAT ADC line */ #define ADC_NUMOF ARRAY_SIZE(adc_config) /** @} */ diff --git a/boards/nucleo-f334r8/include/periph_conf.h b/boards/nucleo-f334r8/include/periph_conf.h index 3beccc5c40..a259fb4475 100644 --- a/boards/nucleo-f334r8/include/periph_conf.h +++ b/boards/nucleo-f334r8/include/periph_conf.h @@ -44,7 +44,7 @@ extern "C" { * Note that we do not configure all ADC channels, * and not in the STM32F334 order. Instead, we * just define 6 ADC channels, for the Nucleo - * Arduino header pins A0-A5 + * Arduino header pins A0-A5 and the internal VBAT channel. * * @{ */ @@ -55,8 +55,10 @@ static const adc_conf_t adc_config[] = { { .pin = GPIO_PIN(PORT_B, 0), .dev = 0, .chan = 11 }, /* ADC1_IN11, slow */ { .pin = GPIO_PIN(PORT_C, 1), .dev = 1, .chan = 7 }, /* ADC12_IN7, slow */ { .pin = GPIO_PIN(PORT_C, 0), .dev = 1, .chan = 6 }, /* ADC12_IN6, slow */ + { .pin = GPIO_UNDEF, .dev = 0, .chan = 17 }, /* VBAT */ }; +#define VBAT_ADC ADC_LINE(6) /**< VBAT ADC line */ #define ADC_NUMOF ARRAY_SIZE(adc_config) /** @} */ diff --git a/boards/nucleo-f401re/include/periph_conf.h b/boards/nucleo-f401re/include/periph_conf.h index 75144e4985..f7988faea2 100644 --- a/boards/nucleo-f401re/include/periph_conf.h +++ b/boards/nucleo-f401re/include/periph_conf.h @@ -243,7 +243,7 @@ static const spi_conf_t spi_config[] = { * Note that we do not configure all ADC channels, * and not in the STM32F401 order. Instead, we * just define 6 ADC channels, for the Nucleo - * Arduino header pins A0-A5 + * Arduino header pins A0-A5 and the internal VBAT channel. * * @{ */ @@ -254,8 +254,10 @@ static const adc_conf_t adc_config[] = { {GPIO_PIN(PORT_B, 0), 0, 8}, {GPIO_PIN(PORT_C, 1), 0, 11}, {GPIO_PIN(PORT_C, 0), 0, 10}, + {GPIO_UNDEF, 0, 18}, /* VBAT */ }; +#define VBAT_ADC ADC_LINE(6) /**< VBAT ADC line */ #define ADC_NUMOF ARRAY_SIZE(adc_config) /** @} */ diff --git a/boards/nucleo-f410rb/include/periph_conf.h b/boards/nucleo-f410rb/include/periph_conf.h index 4f532576ea..c1e33d8591 100644 --- a/boards/nucleo-f410rb/include/periph_conf.h +++ b/boards/nucleo-f410rb/include/periph_conf.h @@ -146,7 +146,7 @@ static const spi_conf_t spi_config[] = { * Note that we do not configure all ADC channels, * and not in the STM32F410 order. Instead, we * just define 6 ADC channels, for the Nucleo - * Arduino header pins A0-A5 + * Arduino header pins A0-A5 and the internal VBAT channel. * * @{ */ @@ -157,8 +157,10 @@ static const adc_conf_t adc_config[] = { {GPIO_PIN(PORT_B, 0), 0, 8}, {GPIO_PIN(PORT_C, 1), 0, 11}, {GPIO_PIN(PORT_C, 0), 0, 10}, + {GPIO_UNDEF, 0, 18}, /* VBAT */ }; +#define VBAT_ADC ADC_LINE(6) /**< VBAT ADC line */ #define ADC_NUMOF ARRAY_SIZE(adc_config) /** @} */ diff --git a/boards/nucleo-f411re/include/periph_conf.h b/boards/nucleo-f411re/include/periph_conf.h index c980f06345..d19cee5ee3 100644 --- a/boards/nucleo-f411re/include/periph_conf.h +++ b/boards/nucleo-f411re/include/periph_conf.h @@ -175,7 +175,7 @@ static const spi_conf_t spi_config[] = { * Note that we do not configure all ADC channels, * and not in the STM32F411 order. Instead, we * just define 6 ADC channels, for the Nucleo - * Arduino header pins A0-A5 + * Arduino header pins A0-A5 and the internal VBAT channel. * * @{ */ @@ -186,8 +186,10 @@ static const adc_conf_t adc_config[] = { {GPIO_PIN(PORT_B, 0), 0, 8}, {GPIO_PIN(PORT_C, 1), 0, 11}, {GPIO_PIN(PORT_C, 0), 0, 10}, + {GPIO_UNDEF, 0, 18}, /* VBAT */ }; +#define VBAT_ADC ADC_LINE(6) /**< VBAT ADC line */ #define ADC_NUMOF ARRAY_SIZE(adc_config) /** @} */ diff --git a/boards/nucleo-f412zg/include/periph_conf.h b/boards/nucleo-f412zg/include/periph_conf.h index 295944522e..24ef5ccc1d 100644 --- a/boards/nucleo-f412zg/include/periph_conf.h +++ b/boards/nucleo-f412zg/include/periph_conf.h @@ -177,7 +177,7 @@ static const spi_conf_t spi_config[] = { * Note that we do not configure all ADC channels, * and not in the STM32F412zg order. Instead, we * just define 6 ADC channels, for the Nucleo - * Arduino header pins A0-A5 + * Arduino header pins A0-A5 and the internal VBAT channel. * * @{ */ @@ -188,8 +188,10 @@ static const adc_conf_t adc_config[] = { {GPIO_PIN(PORT_C, 1), 0, 11}, {GPIO_PIN(PORT_C, 4), 0, 14}, {GPIO_PIN(PORT_C, 5), 0, 15}, + {GPIO_UNDEF, 0, 18}, /* VBAT */ }; +#define VBAT_ADC ADC_LINE(6) /**< VBAT ADC line */ #define ADC_NUMOF ARRAY_SIZE(adc_config) /** @} */ diff --git a/boards/nucleo-f413zh/include/periph_conf.h b/boards/nucleo-f413zh/include/periph_conf.h index f9ac88d1f2..0c890ddd7f 100644 --- a/boards/nucleo-f413zh/include/periph_conf.h +++ b/boards/nucleo-f413zh/include/periph_conf.h @@ -178,7 +178,7 @@ static const spi_conf_t spi_config[] = { * Note that we do not configure all ADC channels, * and not in the STM32F413zh order. Instead, we * just define 6 ADC channels, for the Nucleo - * Arduino header pins A0-A5 + * Arduino header pins A0-A5 and the internal VBAT channel. * * @{ */ @@ -189,8 +189,10 @@ static const adc_conf_t adc_config[] = { {GPIO_PIN(PORT_C, 1), 0, 11}, {GPIO_PIN(PORT_C, 4), 0, 14}, {GPIO_PIN(PORT_C, 5), 0, 15}, + {GPIO_UNDEF, 0, 18}, /* VBAT */ }; +#define VBAT_ADC ADC_LINE(6) /**< VBAT ADC line */ #define ADC_NUMOF ARRAY_SIZE(adc_config) /** @} */ diff --git a/boards/nucleo-f429zi/include/periph_conf.h b/boards/nucleo-f429zi/include/periph_conf.h index a63cec064e..d3c5c94e3c 100644 --- a/boards/nucleo-f429zi/include/periph_conf.h +++ b/boards/nucleo-f429zi/include/periph_conf.h @@ -175,7 +175,7 @@ static const spi_conf_t spi_config[] = { * Note that we do not configure all ADC channels, * and not in the STM32F429zi order. Instead, we * just define 6 ADC channels, for the Nucleo - * Arduino header pins A0-A5 + * Arduino header pins A0-A5 and the internal VBAT channel. * * @{ */ @@ -186,8 +186,10 @@ static const adc_conf_t adc_config[] = { {GPIO_PIN(PORT_F, 3), 2, 9}, {GPIO_PIN(PORT_F, 5), 2, 15}, {GPIO_PIN(PORT_F, 10), 2, 8}, + {GPIO_UNDEF, 0, 18}, /* VBAT */ }; +#define VBAT_ADC ADC_LINE(6) /**< VBAT ADC line */ #define ADC_NUMOF ARRAY_SIZE(adc_config) /** @} */ diff --git a/boards/nucleo-f446re/include/periph_conf.h b/boards/nucleo-f446re/include/periph_conf.h index f6a3270e93..0c5dc8dffd 100644 --- a/boards/nucleo-f446re/include/periph_conf.h +++ b/boards/nucleo-f446re/include/periph_conf.h @@ -253,7 +253,7 @@ static const spi_conf_t spi_config[] = { * Note that we do not configure all ADC channels, * and not in the STM32F446 order. Instead, we * just define 6 ADC channels, for the Nucleo - * Arduino header pins A0-A5 + * Arduino header pins A0-A5 and the internal VBAT channel. * * @{ */ @@ -264,8 +264,10 @@ static const adc_conf_t adc_config[] = { {GPIO_PIN(PORT_B, 0), 0, 8}, {GPIO_PIN(PORT_C, 1), 0, 11}, {GPIO_PIN(PORT_C, 0), 0, 10}, + {GPIO_UNDEF, 0, 18}, /* VBAT */ }; +#define VBAT_ADC ADC_LINE(6) /**< VBAT ADC line */ #define ADC_NUMOF ARRAY_SIZE(adc_config) /** @} */ diff --git a/boards/nucleo-f767zi/include/periph_conf.h b/boards/nucleo-f767zi/include/periph_conf.h index 413af7e7f9..86b2b762ad 100644 --- a/boards/nucleo-f767zi/include/periph_conf.h +++ b/boards/nucleo-f767zi/include/periph_conf.h @@ -193,7 +193,7 @@ static const eth_conf_t eth_config = { * Note that we do not configure all ADC channels, * and not in the STM32F767ZI order. Instead, we * just define 6 ADC channels, for the Nucleo - * Arduino header pins A0-A5 + * Arduino header pins A0-A5 and the internal VBAT channel. * * @{ */ @@ -204,8 +204,10 @@ static const adc_conf_t adc_config[] = { {GPIO_PIN(PORT_F, 3), 2, 9}, {GPIO_PIN(PORT_F, 5), 2, 15}, {GPIO_PIN(PORT_F, 10), 2, 8}, + {GPIO_UNDEF, 0, 18}, /* VBAT */ }; +#define VBAT_ADC ADC_LINE(6) /**< VBAT ADC line */ #define ADC_NUMOF ARRAY_SIZE(adc_config) /** @} */ diff --git a/boards/nucleo-g070rb/include/periph_conf.h b/boards/nucleo-g070rb/include/periph_conf.h index 43d2283200..ef8ef584ad 100644 --- a/boards/nucleo-g070rb/include/periph_conf.h +++ b/boards/nucleo-g070rb/include/periph_conf.h @@ -92,7 +92,7 @@ static const uart_conf_t uart_config[] = { * Note that we do not configure all ADC channels, * and not in the STM32G070 order. Instead, we * just define 6 ADC channels, for the Nucleo - * Arduino header pins A0-A5 + * Arduino header pins A0-A5 and the internal VBAT channel. * * @{ */ @@ -103,8 +103,10 @@ static const adc_conf_t adc_config[] = { { .pin = GPIO_PIN(PORT_B, 1), .dev = 0, .chan = 9 }, { .pin = GPIO_PIN(PORT_B, 11), .dev = 0, .chan = 15 }, { .pin = GPIO_PIN(PORT_B, 12), .dev = 0, .chan = 16 }, + { .pin = GPIO_UNDEF, .dev = 0, .chan = 14}, /* VBAT */ }; +#define VBAT_ADC ADC_LINE(6) /**< VBAT ADC line */ #define ADC_NUMOF ARRAY_SIZE(adc_config) /** @} */ diff --git a/boards/nucleo-g071rb/include/periph_conf.h b/boards/nucleo-g071rb/include/periph_conf.h index 0f72106c73..39c21772db 100644 --- a/boards/nucleo-g071rb/include/periph_conf.h +++ b/boards/nucleo-g071rb/include/periph_conf.h @@ -90,7 +90,7 @@ static const uart_conf_t uart_config[] = { * Note that we do not configure all ADC channels, * and not in the STM32G071 order. Instead, we * just define 6 ADC channels, for the Nucleo - * Arduino header pins A0-A5 + * Arduino header pins A0-A5 and the internal VBAT channel. * * @{ */ @@ -101,8 +101,10 @@ static const adc_conf_t adc_config[] = { { .pin = GPIO_PIN(PORT_B, 1), .dev = 0, .chan = 9 }, { .pin = GPIO_PIN(PORT_B, 11), .dev = 0, .chan = 15 }, { .pin = GPIO_PIN(PORT_B, 12), .dev = 0, .chan = 16 }, + { .pin = GPIO_UNDEF, .dev = 0, .chan = 14}, /* VBAT */ }; +#define VBAT_ADC ADC_LINE(6) /**< VBAT ADC line */ #define ADC_NUMOF ARRAY_SIZE(adc_config) /** @} */ diff --git a/boards/nucleo-l476rg/include/periph_conf.h b/boards/nucleo-l476rg/include/periph_conf.h index 72ffa469ca..73ab16133d 100644 --- a/boards/nucleo-l476rg/include/periph_conf.h +++ b/boards/nucleo-l476rg/include/periph_conf.h @@ -210,6 +210,7 @@ static const spi_conf_t spi_config[] = { * @name ADC configuration * * configure only ADC channels for the Arduino header pins A0-A5 + * and the internal VBAT channel * * @{ */ @@ -220,8 +221,10 @@ static const adc_conf_t adc_config[] = { {GPIO_PIN(PORT_B, 0), 1, 15}, /*< ADC12_IN15 */ {GPIO_PIN(PORT_C, 1), 2, 2}, /*< ADC123_IN_2 */ {GPIO_PIN(PORT_C, 0), 2, 1}, /*< ADC123_IN_1 */ + {GPIO_UNDEF, 0, 18}, /* VBAT */ }; +#define VBAT_ADC ADC_LINE(6) /**< VBAT ADC line */ #define ADC_NUMOF ARRAY_SIZE(adc_config) /** @} */ diff --git a/boards/stm32f0discovery/include/periph_conf.h b/boards/stm32f0discovery/include/periph_conf.h index 80ed7af6fb..0d8edc9614 100644 --- a/boards/stm32f0discovery/include/periph_conf.h +++ b/boards/stm32f0discovery/include/periph_conf.h @@ -96,9 +96,11 @@ static const adc_conf_t adc_config[] = { { GPIO_PIN(PORT_C, 2), 12 }, { GPIO_PIN(PORT_C, 3), 13 }, { GPIO_PIN(PORT_C, 4), 14 }, - { GPIO_PIN(PORT_C, 5), 15 } + { GPIO_PIN(PORT_C, 5), 15 }, + { GPIO_UNDEF, 18 }, /* VBAT */ }; +#define VBAT_ADC ADC_LINE(6) /**< VBAT ADC line */ #define ADC_NUMOF ARRAY_SIZE(adc_config) /** @} */ diff --git a/boards/stm32f469i-disco/include/periph_conf.h b/boards/stm32f469i-disco/include/periph_conf.h index dceeff9271..cda8c0e319 100644 --- a/boards/stm32f469i-disco/include/periph_conf.h +++ b/boards/stm32f469i-disco/include/periph_conf.h @@ -227,7 +227,7 @@ static const pwm_conf_t pwm_config[] = { * @name ADC configuration * * Not all ADCs are configured, by now, only the 6 ones available - * on the Arduino(R) connector A0-A5 + * on the Arduino(R) connector A0-A5 and internal VBAT ADC channel. * @{ */ static const adc_conf_t adc_config[] = { @@ -237,7 +237,10 @@ static const adc_conf_t adc_config[] = { {GPIO_PIN(PORT_C, 4), 2, 14}, {GPIO_PIN(PORT_C, 5), 2, 15}, {GPIO_PIN(PORT_A, 4), 2, 4}, + {GPIO_UNDEF, 0, 18}, /* VBAT */ }; + +#define VBAT_ADC ADC_LINE(6) /**< VBAT ADC line */ #define ADC_NUMOF ARRAY_SIZE(adc_config) /** @} */ diff --git a/boards/stm32f4discovery/include/periph_conf.h b/boards/stm32f4discovery/include/periph_conf.h index db0295dd8c..d2cd062f9c 100644 --- a/boards/stm32f4discovery/include/periph_conf.h +++ b/boards/stm32f4discovery/include/periph_conf.h @@ -131,9 +131,11 @@ static const adc_conf_t adc_config[] = { {GPIO_PIN(PORT_A, 1), 0, 1}, {GPIO_PIN(PORT_A, 4), 0, 4}, {GPIO_PIN(PORT_C, 1), 1, 11}, - {GPIO_PIN(PORT_C, 2), 1, 12} + {GPIO_PIN(PORT_C, 2), 1, 12}, + {GPIO_UNDEF, 0, 18}, /* VBAT */ }; +#define VBAT_ADC ADC_LINE(4) /**< VBAT ADC line */ #define ADC_NUMOF ARRAY_SIZE(adc_config) /** @} */ diff --git a/boards/ublox-c030-u201/include/periph_conf.h b/boards/ublox-c030-u201/include/periph_conf.h index 4a6c166510..be59574078 100644 --- a/boards/ublox-c030-u201/include/periph_conf.h +++ b/boards/ublox-c030-u201/include/periph_conf.h @@ -222,7 +222,7 @@ static const i2c_conf_t i2c_config[] = { * Note that we do not configure all ADC channels, * and not in the STM32F437 order. Instead, we * just define 6 ADC channels, for the - * Arduino header pins A0-A5 + * Arduino header pins A0-A5 and the internal VBAT channel. * * @{ */ @@ -233,8 +233,10 @@ static const adc_conf_t adc_config[] = { {GPIO_PIN(PORT_A, 4), 0, 14}, {GPIO_PIN(PORT_B, 7), 0, 7}, {GPIO_PIN(PORT_B, 6), 0, 6}, + {GPIO_UNDEF, 0, 18}, /* VBAT */ }; +#define VBAT_ADC ADC_LINE(6) /**< VBAT ADC line */ #define ADC_NUMOF ARRAY_SIZE(adc_config) /** @} */ From fa52f1e9860d0b20a4066c56b1eed96720425ebe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20H=C3=BC=C3=9Fler?= Date: Thu, 7 Oct 2021 21:08:27 +0200 Subject: [PATCH 4/6] cpu/stm32: Consider VBAT on CPU init --- cpu/stm32/cpu_init.c | 24 ++++++++++++++++++++---- drivers/periph_common/init.c | 7 +++++++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/cpu/stm32/cpu_init.c b/cpu/stm32/cpu_init.c index b6e7fdd209..c85d3a0f61 100644 --- a/cpu/stm32/cpu_init.c +++ b/cpu/stm32/cpu_init.c @@ -38,6 +38,7 @@ #include "periph_cpu.h" #include "periph/init.h" #include "periph/gpio.h" +#include "periph/vbat.h" #include "board.h" #include "pm_layered.h" @@ -395,14 +396,29 @@ void backup_ram_init(void) #define BACKUP_RAM_MAGIC {'R', 'I', 'O', 'T'} #endif -bool cpu_woke_from_backup(void) -{ +static inline bool _backup_battery_connected(void) { +#if IS_USED(MODULE_PERIPH_VBAT) + vbat_init(); /* early use of VBAT requires init() */ + return !vbat_is_empty(); +#endif + return false; +} + +bool cpu_woke_from_backup(void) { #if IS_ACTIVE(CPU_HAS_BACKUP_RAM) static const char _signature[] BACKUP_RAM_DATA = BACKUP_RAM_MAGIC; - /* switch off regulator to save power */ + if (_backup_battery_connected()) { + /* in case the board has a backup battery the regulator must be on + to mitigate (unexpected) outage of VDD, so RTC register and + backup domain register contents are not lost */ + pm_backup_regulator_on(); + } + else { #ifndef RIOTBOOT - pm_backup_regulator_off(); + /* switch off regulator to save power */ + pm_backup_regulator_off(); #endif + } for (unsigned i = 0; i < sizeof(_signature); i++) { if (_signature[i] != ((char[])BACKUP_RAM_MAGIC)[i]) { return false; diff --git a/drivers/periph_common/init.c b/drivers/periph_common/init.c index 8fbd394f30..9d88170b72 100644 --- a/drivers/periph_common/init.c +++ b/drivers/periph_common/init.c @@ -50,6 +50,9 @@ #ifdef MODULE_PERIPH_INIT_PTP #include "periph/ptp.h" #endif +#ifdef MODULE_PERIPH_INIT_VBAT +#include "periph/vbat.h" +#endif #endif /* MODULE_PERIPH_INIT */ void periph_init(void) @@ -105,5 +108,9 @@ void periph_init(void) ptp_init(); #endif +#if defined(MODULE_PERIPH_INIT_VBAT) + vbat_init(); +#endif + #endif /* MODULE_PERIPH_INIT */ } From 2775c720185770a858173798f92469a66f2b22b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20H=C3=BC=C3=9Fler?= Date: Sun, 10 Oct 2021 17:33:28 +0200 Subject: [PATCH 5/6] tests/driver_vbat: add test for backup battery monitoring --- tests/periph_vbat/Makefile | 6 +++++ tests/periph_vbat/README.md | 5 ++++ tests/periph_vbat/app.config.test | 5 ++++ tests/periph_vbat/main.c | 42 +++++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+) create mode 100644 tests/periph_vbat/Makefile create mode 100644 tests/periph_vbat/README.md create mode 100644 tests/periph_vbat/app.config.test create mode 100644 tests/periph_vbat/main.c diff --git a/tests/periph_vbat/Makefile b/tests/periph_vbat/Makefile new file mode 100644 index 0000000000..ba1d50c726 --- /dev/null +++ b/tests/periph_vbat/Makefile @@ -0,0 +1,6 @@ +include ../Makefile.tests_common + +FEATURES_REQUIRED += periph_vbat +USEMODULE += ztimer ztimer_msec + +include $(RIOTBASE)/Makefile.include diff --git a/tests/periph_vbat/README.md b/tests/periph_vbat/README.md new file mode 100644 index 0000000000..77299e3e49 --- /dev/null +++ b/tests/periph_vbat/README.md @@ -0,0 +1,5 @@ +Backup Battery Monitoring Application +===================================== + +This test regularly samples the backup battery voltage and prints the result +to the serial console. diff --git a/tests/periph_vbat/app.config.test b/tests/periph_vbat/app.config.test new file mode 100644 index 0000000000..53f7c7a820 --- /dev/null +++ b/tests/periph_vbat/app.config.test @@ -0,0 +1,5 @@ +# this file enables modules defined in Kconfig. Do not use this file for +# application configuration. This is only needed during migration. +CONFIG_MODULE_ZTIMER=y +CONFIG_MODULE_ZTIMER_MSEC=y +CONFIG_MODULE_PERIPH_VBAT=y diff --git a/tests/periph_vbat/main.c b/tests/periph_vbat/main.c new file mode 100644 index 0000000000..47d7988fea --- /dev/null +++ b/tests/periph_vbat/main.c @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2022 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup tests + * @{ + * + * @file + * @brief Test application for backup battery monitoring + * + * @author Fabian Hüßler + * + * @} + */ + +#include +#include + +#include "board.h" +#include "ztimer.h" +#include "periph/vbat.h" + +int main(void) +{ + puts("\nRIOT backup battery monitoring test\n"); + puts("This test will sample the backup battery once a second\n\n"); + + int32_t bat_mv; + while (1) { + if ((bat_mv = vbat_sample_mv()) < 0) { + return 1; + } + printf("VBAT: %"PRIi32"[mV]\n", bat_mv); + ztimer_sleep(ZTIMER_MSEC, 1000); + } + return 0; +} From e3509fc0239a88cf74166468db82f68644ca17d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20H=C3=BC=C3=9Fler?= Date: Sun, 23 Jan 2022 10:40:51 +0100 Subject: [PATCH 6/6] cpu/stm32: add sampling time to F4/F7 ADC driver --- cpu/stm32/periph/adc_f4_f7.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/cpu/stm32/periph/adc_f4_f7.c b/cpu/stm32/periph/adc_f4_f7.c index 64c489a6b1..a36a80282a 100644 --- a/cpu/stm32/periph/adc_f4_f7.c +++ b/cpu/stm32/periph/adc_f4_f7.c @@ -30,6 +30,12 @@ */ #define MAX_ADC_SPEED (12000000U) +/** + * @brief Maximum sampling time for each channel (480 cycles) + * T_CONV[µs] = (RESOLUTION[bits] + SMP[cycles]) / CLOCK_SPEED[MHz] + */ +#define MAX_ADC_SMP (7u) + /** * @brief Default VBAT undefined value */ @@ -93,7 +99,15 @@ int adc_init(adc_t line) } } ADC->CCR = ((clk_div / 2) - 1) << 16; - + /* set sampling time to the maximum */ + if (adc_config[line].chan >= 10) { + dev(line)->SMPR1 &= ~(MAX_ADC_SMP << (3 * (adc_config[line].chan - 10))); + dev(line)->SMPR1 |= MAX_ADC_SMP << (3 * (adc_config[line].chan - 10)); + } + else { + dev(line)->SMPR1 &= ~(MAX_ADC_SMP << (3 * adc_config[line].chan)); + dev(line)->SMPR2 |= MAX_ADC_SMP << (3 * adc_config[line].chan); + } /* free the device again */ done(line); return 0;