diff --git a/cpu/atmega1281/include/periph_cpu.h b/cpu/atmega1281/include/periph_cpu.h index cec8221dbe..eab61b47dd 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 b2f292a624..cf6f3a76d1 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 349b04c071..4e3c4f709c 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 7a4d546a52..df606bfbd9 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 496ffe901b..6e42eba920 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 b9c2423d0c..d53e5496a0 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 8429e00e2c..be2d71df4d 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/atmega8/include/periph_cpu.h b/cpu/atmega8/include/periph_cpu.h index d8666c83ed..32b6c51ebf 100644 --- a/cpu/atmega8/include/periph_cpu.h +++ b/cpu/atmega8/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/atxmega/Kconfig b/cpu/atxmega/Kconfig index 09d699cbe4..19495de1d0 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 43da1e7f66..55c0238cbf 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 7908685a4f..d566d9ce38 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 3360051f8b..0000000000 --- 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 440f09266a..72219bae38 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 e002715cde..af072b0071 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 54bd222d82..03a0f40b5a 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 4b36b1f63a..3920b1bb4c 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 80c7f8d197..a1a228d518 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 1c5acda5cd..c9f934217d 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 0000000000..2bc22c6261 --- /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 5cfeca21d0..6e183661e7 100644 --- a/cpu/avr8_common/include/cpu.h +++ b/cpu/avr8_common/include/cpu.h @@ -48,6 +48,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 0000000000..17750d59e9 --- /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 0000000000..ce4c195b0e --- /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 0000000000..1d31fd0833 --- /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(); +}