From 211ac407cc457d1a01d43630312cef68a2d70f3c Mon Sep 17 00:00:00 2001 From: Gerson Fernando Budke Date: Thu, 20 Oct 2022 18:50:22 +0200 Subject: [PATCH] cpu/avr8: Enable PM periph to all SoC This refactor the current xmega PM peripheral to avr8 common and extend PM to cpus families. Signed-off-by: Gerson Fernando Budke --- cpu/atmega1281/include/periph_cpu.h | 11 ++++ cpu/atmega1284p/include/periph_cpu.h | 11 ++++ cpu/atmega128rfa1/include/periph_cpu.h | 10 ++++ cpu/atmega2560/include/periph_cpu.h | 11 ++++ cpu/atmega256rfr2/include/periph_cpu.h | 11 ++++ cpu/atmega328p/include/periph_cpu.h | 11 ++++ cpu/atmega32u4/include/periph_cpu.h | 11 ++++ cpu/atxmega/Kconfig | 1 - cpu/atxmega/Makefile.dep | 3 - cpu/atxmega/Makefile.features | 1 - cpu/atxmega/atxmega.config | 2 - cpu/atxmega/include/periph_cpu.h | 4 ++ cpu/atxmega/periph/pm.c | 40 ------------- cpu/avr8_common/Kconfig | 1 + cpu/avr8_common/Makefile | 2 +- cpu/avr8_common/Makefile.dep | 5 +- cpu/avr8_common/Makefile.features | 1 + cpu/avr8_common/avr8_common.config | 2 + cpu/avr8_common/include/cpu.h | 9 +++ cpu/avr8_common/periph/Kconfig | 7 +++ cpu/avr8_common/periph/Makefile | 3 + cpu/avr8_common/periph/pm.c | 83 ++++++++++++++++++++++++++ 22 files changed, 191 insertions(+), 49 deletions(-) delete mode 100644 cpu/atxmega/atxmega.config create mode 100644 cpu/avr8_common/avr8_common.config create mode 100644 cpu/avr8_common/periph/Kconfig create mode 100644 cpu/avr8_common/periph/Makefile create mode 100644 cpu/avr8_common/periph/pm.c diff --git a/cpu/atmega1281/include/periph_cpu.h b/cpu/atmega1281/include/periph_cpu.h index cec8221dbe098..eab61b47dde51 100644 --- a/cpu/atmega1281/include/periph_cpu.h +++ b/cpu/atmega1281/include/periph_cpu.h @@ -29,6 +29,17 @@ extern "C" { #include "periph_cpu_common.h" +/** + * @name Power management configuration + * @{ + */ +#define PM_NUM_MODES (5) +#define AVR8_PM_SLEEP_MODE_0 SLEEP_MODE_PWR_DOWN /**< Power Down */ +#define AVR8_PM_SLEEP_MODE_1 SLEEP_MODE_PWR_SAVE /**< Power Save */ +#define AVR8_PM_SLEEP_MODE_2 SLEEP_MODE_STANDBY /**< Standby */ +#define AVR8_PM_SLEEP_MODE_3 SLEEP_MODE_ADC /**< Sleep ADC low noise */ +/** @} */ + /** * @brief Available ports on the ATmega1281 family */ diff --git a/cpu/atmega1284p/include/periph_cpu.h b/cpu/atmega1284p/include/periph_cpu.h index b2f292a6240af..cf6f3a76d16d1 100644 --- a/cpu/atmega1284p/include/periph_cpu.h +++ b/cpu/atmega1284p/include/periph_cpu.h @@ -29,6 +29,17 @@ extern "C" { #endif +/** + * @name Power management configuration + * @{ + */ +#define PM_NUM_MODES (5) +#define AVR8_PM_SLEEP_MODE_0 SLEEP_MODE_PWR_DOWN /**< Power Down */ +#define AVR8_PM_SLEEP_MODE_1 SLEEP_MODE_PWR_SAVE /**< Power Save */ +#define AVR8_PM_SLEEP_MODE_2 SLEEP_MODE_STANDBY /**< Standby */ +#define AVR8_PM_SLEEP_MODE_3 SLEEP_MODE_ADC /**< Sleep ADC low noise */ +/** @} */ + /** * @brief Define a CPU specific GPIO pin generator macro */ diff --git a/cpu/atmega128rfa1/include/periph_cpu.h b/cpu/atmega128rfa1/include/periph_cpu.h index 349b04c0714f4..4e3c4f709c3f1 100644 --- a/cpu/atmega128rfa1/include/periph_cpu.h +++ b/cpu/atmega128rfa1/include/periph_cpu.h @@ -26,6 +26,16 @@ #ifdef __cplusplus extern "C" { #endif +/** + * @name Power management configuration + * @{ + */ +#define PM_NUM_MODES (5) +#define AVR8_PM_SLEEP_MODE_0 SLEEP_MODE_PWR_DOWN /**< Power Down */ +#define AVR8_PM_SLEEP_MODE_1 SLEEP_MODE_PWR_SAVE /**< Power Save */ +#define AVR8_PM_SLEEP_MODE_2 SLEEP_MODE_STANDBY /**< Standby */ +#define AVR8_PM_SLEEP_MODE_3 SLEEP_MODE_ADC /**< Sleep ADC low noise */ +/** @} */ /** * @name Available ports on the ATmega128rfa1 MCU diff --git a/cpu/atmega2560/include/periph_cpu.h b/cpu/atmega2560/include/periph_cpu.h index 7a4d546a5208a..df606bfbd9014 100644 --- a/cpu/atmega2560/include/periph_cpu.h +++ b/cpu/atmega2560/include/periph_cpu.h @@ -27,6 +27,17 @@ extern "C" { #endif +/** + * @name Power management configuration + * @{ + */ +#define PM_NUM_MODES (5) +#define AVR8_PM_SLEEP_MODE_0 SLEEP_MODE_PWR_DOWN /**< Power Down */ +#define AVR8_PM_SLEEP_MODE_1 SLEEP_MODE_PWR_SAVE /**< Power Save */ +#define AVR8_PM_SLEEP_MODE_2 SLEEP_MODE_STANDBY /**< Standby */ +#define AVR8_PM_SLEEP_MODE_3 SLEEP_MODE_ADC /**< Sleep ADC low noise */ +/** @} */ + /** * @brief Available ports on the ATmega2560 family */ diff --git a/cpu/atmega256rfr2/include/periph_cpu.h b/cpu/atmega256rfr2/include/periph_cpu.h index 496ffe901b405..6e42eba9206d1 100644 --- a/cpu/atmega256rfr2/include/periph_cpu.h +++ b/cpu/atmega256rfr2/include/periph_cpu.h @@ -27,6 +27,17 @@ extern "C" { #endif +/** + * @name Power management configuration + * @{ + */ +#define PM_NUM_MODES (5) +#define AVR8_PM_SLEEP_MODE_0 SLEEP_MODE_PWR_DOWN /**< Power Down */ +#define AVR8_PM_SLEEP_MODE_1 SLEEP_MODE_PWR_SAVE /**< Power Save */ +#define AVR8_PM_SLEEP_MODE_2 SLEEP_MODE_STANDBY /**< Standby */ +#define AVR8_PM_SLEEP_MODE_3 SLEEP_MODE_ADC /**< Sleep ADC low noise */ +/** @} */ + /** * @name Available ports on the ATmega256rfr family * @{ diff --git a/cpu/atmega328p/include/periph_cpu.h b/cpu/atmega328p/include/periph_cpu.h index b9c2423d0c0bf..d53e5496a0f29 100644 --- a/cpu/atmega328p/include/periph_cpu.h +++ b/cpu/atmega328p/include/periph_cpu.h @@ -27,6 +27,17 @@ extern "C" { #endif +/** + * @name Power management configuration + * @{ + */ +#define PM_NUM_MODES (5) +#define AVR8_PM_SLEEP_MODE_0 SLEEP_MODE_PWR_DOWN /**< Power Down */ +#define AVR8_PM_SLEEP_MODE_1 SLEEP_MODE_PWR_SAVE /**< Power Save */ +#define AVR8_PM_SLEEP_MODE_2 SLEEP_MODE_STANDBY /**< Standby */ +#define AVR8_PM_SLEEP_MODE_3 SLEEP_MODE_ADC /**< Sleep ADC low noise */ +/** @} */ + /** * @brief Define a CPU specific GPIO pin generator macro */ diff --git a/cpu/atmega32u4/include/periph_cpu.h b/cpu/atmega32u4/include/periph_cpu.h index 8429e00e2c50a..be2d71df4dcfd 100644 --- a/cpu/atmega32u4/include/periph_cpu.h +++ b/cpu/atmega32u4/include/periph_cpu.h @@ -26,6 +26,17 @@ extern "C" { #endif +/** + * @name Power management configuration + * @{ + */ +#define PM_NUM_MODES (5) +#define AVR8_PM_SLEEP_MODE_0 SLEEP_MODE_PWR_DOWN /**< Power Down */ +#define AVR8_PM_SLEEP_MODE_1 SLEEP_MODE_PWR_SAVE /**< Power Save */ +#define AVR8_PM_SLEEP_MODE_2 SLEEP_MODE_STANDBY /**< Standby */ +#define AVR8_PM_SLEEP_MODE_3 SLEEP_MODE_ADC /**< Sleep ADC low noise */ +/** @} */ + /** * @brief Available ports on the ATmega32u4 family */ diff --git a/cpu/atxmega/Kconfig b/cpu/atxmega/Kconfig index 09d699cbe42b5..19495de1d05b9 100644 --- a/cpu/atxmega/Kconfig +++ b/cpu/atxmega/Kconfig @@ -19,7 +19,6 @@ config CPU_COMMON_ATXMEGA select HAS_PERIPH_GPIO select HAS_PERIPH_GPIO_IRQ select HAS_PERIPH_NVM - select HAS_PERIPH_PM select HAS_PERIPH_TIMER select HAS_PERIPH_TIMER_PERIODIC diff --git a/cpu/atxmega/Makefile.dep b/cpu/atxmega/Makefile.dep index 43da1e7f66f3f..55c0238cbf0bb 100644 --- a/cpu/atxmega/Makefile.dep +++ b/cpu/atxmega/Makefile.dep @@ -1,9 +1,6 @@ # peripheral drivers are linked into the final binary USEMODULE += atxmega_periph -# All ATxmega based CPUs provide PM -USEMODULE += pm_layered - ifneq (,$(filter periph_cpuid,$(USEMODULE))) USEMODULE += periph_nvm endif diff --git a/cpu/atxmega/Makefile.features b/cpu/atxmega/Makefile.features index 7908685a4f807..d566d9ce38b85 100644 --- a/cpu/atxmega/Makefile.features +++ b/cpu/atxmega/Makefile.features @@ -11,7 +11,6 @@ FEATURES_PROVIDED += cpu_core_atxmega FEATURES_PROVIDED += periph_cpuid FEATURES_PROVIDED += periph_gpio periph_gpio_irq FEATURES_PROVIDED += periph_nvm -FEATURES_PROVIDED += periph_pm FEATURES_PROVIDED += periph_timer periph_timer_periodic # Add atxmega configurations. This configuration enables modules that are only available when diff --git a/cpu/atxmega/atxmega.config b/cpu/atxmega/atxmega.config deleted file mode 100644 index 3360051f8bebd..0000000000000 --- a/cpu/atxmega/atxmega.config +++ /dev/null @@ -1,2 +0,0 @@ -# All ATxmega based CPUs provide PM -CONFIG_MODULE_PM_LAYERED=y diff --git a/cpu/atxmega/include/periph_cpu.h b/cpu/atxmega/include/periph_cpu.h index 440f09266a9b0..72219bae38c59 100644 --- a/cpu/atxmega/include/periph_cpu.h +++ b/cpu/atxmega/include/periph_cpu.h @@ -96,6 +96,10 @@ enum { * @{ */ #define PM_NUM_MODES (5) +#define AVR8_PM_SLEEP_MODE_0 SLEEP_MODE_PWR_DOWN /**< Power Down */ +#define AVR8_PM_SLEEP_MODE_1 SLEEP_MODE_PWR_SAVE /**< Power Save */ +#define AVR8_PM_SLEEP_MODE_2 SLEEP_MODE_STANDBY /**< Standby */ +#define AVR8_PM_SLEEP_MODE_3 SLEEP_MODE_EXT_STANDBY /**< Extended Standby*/ /** @} */ /** diff --git a/cpu/atxmega/periph/pm.c b/cpu/atxmega/periph/pm.c index e002715cde0c7..af072b0071636 100644 --- a/cpu/atxmega/periph/pm.c +++ b/cpu/atxmega/periph/pm.c @@ -19,8 +19,6 @@ * @} */ -#include - #include "cpu_pm.h" #include "irq.h" #include "periph/pm.h" @@ -73,44 +71,6 @@ void pm_reboot(void) while (1) {} } -/* - * DEBUG may affect this routine. - * - * --- Do NOT add DEBUG macro here --- - * - */ -void pm_set(unsigned mode) -{ - unsigned irq_state = irq_disable(); - - if (avr8_is_uart_tx_pending() && mode < 4) { - irq_restore(irq_state); - return; - } - - switch (mode) { - case 0: - set_sleep_mode(SLEEP_SMODE_PDOWN_gc); - break; - case 1: - set_sleep_mode(SLEEP_SMODE_PSAVE_gc); - break; - case 2: - set_sleep_mode(SLEEP_SMODE_STDBY_gc); - break; - case 3: - set_sleep_mode(SLEEP_SMODE_ESTDBY_gc); - break; - default: - set_sleep_mode(SLEEP_SMODE_IDLE_gc); - } - sleep_enable(); - sei(); - sleep_cpu(); - sleep_disable(); - irq_restore(irq_state); -} - void pm_periph_enable(pwr_reduction_t pwr) { uint8_t mask = _device_mask(pwr); diff --git a/cpu/avr8_common/Kconfig b/cpu/avr8_common/Kconfig index 54bd222d82ac8..03a0f40b5a9fe 100644 --- a/cpu/avr8_common/Kconfig +++ b/cpu/avr8_common/Kconfig @@ -10,6 +10,7 @@ config CPU_ARCH_AVR8 bool select HAS_ARCH_8BIT select HAS_ARCH_AVR8 + select HAS_PERIPH_PM select MODULE_MALLOC_THREAD_SAFE if TEST_KCONFIG select MODULE_TINY_STRERROR_AS_STRERROR if TEST_KCONFIG diff --git a/cpu/avr8_common/Makefile b/cpu/avr8_common/Makefile index 4b36b1f63ac46..3920b1bb4c5bc 100644 --- a/cpu/avr8_common/Makefile +++ b/cpu/avr8_common/Makefile @@ -2,6 +2,6 @@ MODULE = avr8_common # add a list of subdirectories, that should also be build -DIRS = avr_libc_extra +DIRS = periph avr_libc_extra include $(RIOTBASE)/Makefile.base diff --git a/cpu/avr8_common/Makefile.dep b/cpu/avr8_common/Makefile.dep index 80c7f8d197252..a1a228d518c08 100644 --- a/cpu/avr8_common/Makefile.dep +++ b/cpu/avr8_common/Makefile.dep @@ -2,7 +2,10 @@ USEMODULE += avr_libc_extra # tell the build system to build the avr8 common files -USEMODULE += avr8_common +USEMODULE += avr8_common avr8_common_periph + +# All avr8 CPUs provide PM +USEMODULE += pm_layered # The AVR-libc provides no thread safe malloc implementation and has no hooks # to inject. Use malloc_thread_safe to link calls to malloc to safe wrappers diff --git a/cpu/avr8_common/Makefile.features b/cpu/avr8_common/Makefile.features index 1c5acda5cd1db..c9f934217d040 100644 --- a/cpu/avr8_common/Makefile.features +++ b/cpu/avr8_common/Makefile.features @@ -1,3 +1,4 @@ FEATURES_PROVIDED += arch_8bit FEATURES_PROVIDED += arch_avr8 FEATURES_PROVIDED += cpp +FEATURES_PROVIDED += periph_pm diff --git a/cpu/avr8_common/avr8_common.config b/cpu/avr8_common/avr8_common.config new file mode 100644 index 0000000000000..2bc22c6261f4d --- /dev/null +++ b/cpu/avr8_common/avr8_common.config @@ -0,0 +1,2 @@ +# All AVR-8 based CPUs provide PM +CONFIG_MODULE_PM_LAYERED=y diff --git a/cpu/avr8_common/include/cpu.h b/cpu/avr8_common/include/cpu.h index 18c4dcee71416..4d6e38ba19c4a 100644 --- a/cpu/avr8_common/include/cpu.h +++ b/cpu/avr8_common/include/cpu.h @@ -47,6 +47,15 @@ extern "C" { #endif +/** + * @name BOD monitoring when CPU is on sleep + * @{ + */ +#ifndef AVR8_PM_DISABLE_BOD_ON_SLEEP +#define AVR8_PM_DISABLE_BOD_ON_SLEEP 0 /**< BOD is active on sleep */ +#endif +/** @} */ + /** * @name Use shared I2C functions * @{ diff --git a/cpu/avr8_common/periph/Kconfig b/cpu/avr8_common/periph/Kconfig new file mode 100644 index 0000000000000..17750d59e9b6d --- /dev/null +++ b/cpu/avr8_common/periph/Kconfig @@ -0,0 +1,7 @@ +config MODULE_AVR8_COMMON_PERIPH + bool + depends on TEST_KCONFIG + depends on CPU_COMMON_ATXMEGA + default y + help + AVR8 common peripheral drivers. diff --git a/cpu/avr8_common/periph/Makefile b/cpu/avr8_common/periph/Makefile new file mode 100644 index 0000000000000..ce4c195b0e3b0 --- /dev/null +++ b/cpu/avr8_common/periph/Makefile @@ -0,0 +1,3 @@ +MODULE = avr8_common_periph + +include $(RIOTMAKE)/periph.mk diff --git a/cpu/avr8_common/periph/pm.c b/cpu/avr8_common/periph/pm.c new file mode 100644 index 0000000000000..1d31fd0833100 --- /dev/null +++ b/cpu/avr8_common/periph/pm.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2022-2023 Gerson Fernando Budke + * + * 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_avr8_common + * @ingroup cpu_avr8_common_periph + * @{ + * + * @file + * @brief Low-level PM driver implementation + * + * @author Gerson Fernando Budke + * + * @} + */ + +#include + +#include "irq.h" +#include "periph_cpu.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +/** + * @note: The pm_set assumes that interrupts are disable and there is no reason + * to save SREG here. + * + * @note: DEBUG affects this routine. + */ +void pm_set(unsigned mode) +{ + DEBUG("pm_set(%d)\n", mode); + + if (avr8_is_uart_tx_pending()) { + mode = PM_NUM_MODES - 1; + } + + switch (mode) { + case 0: + set_sleep_mode(AVR8_PM_SLEEP_MODE_0); + break; +#if PM_NUM_MODES > 1 + case 1: + set_sleep_mode(AVR8_PM_SLEEP_MODE_1); + break; +#endif +#if PM_NUM_MODES > 2 + case 2: + set_sleep_mode(AVR8_PM_SLEEP_MODE_2); + break; +#endif +#if PM_NUM_MODES > 3 + case 3: + set_sleep_mode(AVR8_PM_SLEEP_MODE_3); + break; +#endif + default: + set_sleep_mode(SLEEP_MODE_IDLE); + break; + } + + DEBUG("mode selected: %d\n", mode); + +/* + * Critical Section to correct enable SLEEP instruction on RIOT-OS + */ +#if (AVR8_PM_DISABLE_BOD_ON_SLEEP == 1) +#ifdef sleep_bod_disable + sleep_bod_disable(); +#endif +#endif + sleep_enable(); + sei(); + sleep_cpu(); + cli(); + sleep_disable(); +}