mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #17895 from benpicco/pm_blocker_array
sys/pm_layered: use array representation, get rid of implicit IDLE mode
This commit is contained in:
commit
f3ffe134b0
@ -95,7 +95,7 @@ enum {
|
||||
* @name Power management configuration
|
||||
* @{
|
||||
*/
|
||||
#define PM_NUM_MODES (4)
|
||||
#define PM_NUM_MODES (5)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -56,7 +56,7 @@ typedef uint32_t gpio_t;
|
||||
* @name Power mode configuration
|
||||
* @{
|
||||
*/
|
||||
#define PM_NUM_MODES (4)
|
||||
#define PM_NUM_MODES (5)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -452,7 +452,7 @@ typedef struct {
|
||||
/**
|
||||
* @brief Number of usable power modes.
|
||||
*/
|
||||
#define PM_NUM_MODES (2U)
|
||||
#define PM_NUM_MODES (3U)
|
||||
|
||||
/**
|
||||
* @name Watchdog timer (WDT) configuration
|
||||
|
@ -38,7 +38,7 @@ extern "C" {
|
||||
/**
|
||||
* @brief Number of usable low power modes
|
||||
*/
|
||||
#define PM_NUM_MODES (2U)
|
||||
#define PM_NUM_MODES (3U)
|
||||
|
||||
/**
|
||||
* @name Power modes
|
||||
|
@ -148,7 +148,7 @@ typedef uint32_t spi_cs_t;
|
||||
* @name Kinetis power mode configuration
|
||||
* @{
|
||||
*/
|
||||
#define PM_NUM_MODES (3U)
|
||||
#define PM_NUM_MODES (4U)
|
||||
enum {
|
||||
KINETIS_PM_LLS = 0,
|
||||
KINETIS_PM_VLPS = 1,
|
||||
|
@ -73,7 +73,7 @@ typedef enum {
|
||||
/**
|
||||
* @brief Power management configuration
|
||||
*/
|
||||
#define PM_NUM_MODES (2U)
|
||||
#define PM_NUM_MODES (3U)
|
||||
|
||||
/**
|
||||
* @brief UART device configuration
|
||||
|
@ -36,7 +36,7 @@ extern "C" {
|
||||
* @name Power mode configuration
|
||||
* @{
|
||||
*/
|
||||
#define PM_NUM_MODES (3)
|
||||
#define PM_NUM_MODES (4)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -32,15 +32,15 @@ extern "C" {
|
||||
* @name Power mode configuration
|
||||
* @{
|
||||
*/
|
||||
#define PM_NUM_MODES (3)
|
||||
#define PM_NUM_MODES (4)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Override the default initial PM blocker
|
||||
* @todo Idle modes are enabled by default, deep sleep mode blocked
|
||||
* Idle modes are enabled by default, deep sleep mode blocked
|
||||
*/
|
||||
#ifndef PM_BLOCKER_INITIAL
|
||||
#define PM_BLOCKER_INITIAL 0x00000001
|
||||
#define PM_BLOCKER_INITIAL { 1, 0, 0, 0 }
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
@ -53,11 +53,7 @@ extern "C" {
|
||||
* @name Power mode configuration
|
||||
* @{
|
||||
*/
|
||||
#define PM_NUM_MODES 4 /**< Backup, Hibernate, Standby, Idle */
|
||||
|
||||
#ifndef PM_BLOCKER_INITIAL
|
||||
#define PM_BLOCKER_INITIAL 0x00010101 /**< Block all modes but Idle */
|
||||
#endif
|
||||
#define PM_NUM_MODES (4) /**< Backup, Hibernate, Standby, Idle */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -30,17 +30,9 @@ extern "C" {
|
||||
* @name Power mode configuration
|
||||
* @{
|
||||
*/
|
||||
#define PM_NUM_MODES (1)
|
||||
#define PM_NUM_MODES (2)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Override the default initial PM blocker
|
||||
* @todo Idle modes are enabled by default, deep sleep mode blocked
|
||||
*/
|
||||
#ifndef PM_BLOCKER_INITIAL
|
||||
#define PM_BLOCKER_INITIAL 0x00000001
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @name SAML1x GCLK definitions
|
||||
* @{
|
||||
|
@ -35,7 +35,7 @@ extern "C" {
|
||||
* @name Power mode configuration
|
||||
* @{
|
||||
*/
|
||||
#define PM_NUM_MODES (2)
|
||||
#define PM_NUM_MODES (3)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -32,14 +32,15 @@ extern "C" {
|
||||
/**
|
||||
* @brief Number of usable low power modes
|
||||
*/
|
||||
#define PM_NUM_MODES (2U)
|
||||
#define PM_NUM_MODES (3U)
|
||||
|
||||
/**
|
||||
* @name Power modes
|
||||
* @{
|
||||
*/
|
||||
#define STM32_PM_STOP (1U) /**< Index of STOP mode */
|
||||
#define STM32_PM_STANDBY (0U) /**< Index of STANDBY mode */
|
||||
#define STM32_PM_IDLE (2U) /**< Index of IDLE mode */
|
||||
#define STM32_PM_STOP (1U) /**< Index of STOP mode */
|
||||
#define STM32_PM_STANDBY (0U) /**< Index of STANDBY mode */
|
||||
/** @} */
|
||||
|
||||
#ifndef PM_EWUP_CONFIG
|
||||
|
@ -53,10 +53,6 @@ else ifeq (abp,$(ACTIVATION_MODE))
|
||||
CFLAGS += -DUSE_ABP
|
||||
endif
|
||||
|
||||
# Enable deep sleep power mode (e.g. STOP mode on STM32) which
|
||||
# in general provides RAM retention after wake-up.
|
||||
CFLAGS += -DPM_BLOCKER_INITIAL=0x00000001
|
||||
|
||||
# Comment this out to disable code in RIOT that does safety checking
|
||||
# which is not needed in a production environment but helps in the
|
||||
# development process:
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "thread.h"
|
||||
#include "fmt.h"
|
||||
|
||||
#include "periph/pm.h"
|
||||
#if IS_USED(MODULE_PERIPH_RTC)
|
||||
#include "periph/rtc.h"
|
||||
#else
|
||||
@ -148,6 +149,16 @@ int main(void)
|
||||
puts("LoRaWAN Class A low-power application");
|
||||
puts("=====================================");
|
||||
|
||||
/*
|
||||
* Enable deep sleep power mode (e.g. STOP mode on STM32) which
|
||||
* in general provides RAM retention after wake-up.
|
||||
*/
|
||||
#if IS_USED(MODULE_PM_LAYERED)
|
||||
for (unsigned i = 1; i < PM_NUM_MODES; ++i) {
|
||||
pm_unblock(i);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Initialize the radio driver */
|
||||
#if IS_USED(MODULE_SX127X)
|
||||
sx127x_setup(&sx127x, &sx127x_params[0], 0);
|
||||
|
@ -16,9 +16,10 @@
|
||||
*
|
||||
* This simple power management interface is based on the following assumptions:
|
||||
*
|
||||
* - CPUs define up to 4 power modes (from zero, the lowest power mode, to
|
||||
* PM_NUM_MODES-1, the highest)
|
||||
* - there is an implicit extra idle mode (which has the number PM_NUM_MODES)
|
||||
* - CPUs define a number of power modes (from zero, the lowest power mode, to
|
||||
* PM_NUM_MODES, the highest)
|
||||
* - there is an implicit extra busy-wait mode (which has the number PM_NUM_MODES)
|
||||
* where the CPU is kept spinning if all modes are blocked.
|
||||
* - individual power modes can be blocked/unblocked, e.g., by peripherals
|
||||
* - if a mode is blocked, so are implicitly all lower modes
|
||||
* - the idle thread automatically selects and sets the lowest unblocked mode
|
||||
@ -52,9 +53,8 @@ extern "C" {
|
||||
/**
|
||||
* @brief Power Management mode blocker typedef
|
||||
*/
|
||||
typedef union {
|
||||
uint32_t val_u32; /**< power mode blockers u32 */
|
||||
uint8_t val_u8[PM_NUM_MODES]; /**< power mode blockers u8 */
|
||||
typedef struct {
|
||||
uint8_t blockers[PM_NUM_MODES]; /**< number of blockers for the mode */
|
||||
} pm_blocker_t;
|
||||
|
||||
/**
|
||||
|
@ -19,9 +19,9 @@
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "board.h"
|
||||
#include "atomic_utils.h"
|
||||
#include "irq.h"
|
||||
#include "periph/pm.h"
|
||||
#include "pm_layered.h"
|
||||
@ -34,58 +34,73 @@
|
||||
#endif
|
||||
|
||||
#ifndef PM_BLOCKER_INITIAL
|
||||
#define PM_BLOCKER_INITIAL 0x01010101 /* block all by default */
|
||||
#if PM_NUM_MODES == 1
|
||||
#define PM_BLOCKER_INITIAL { 0 }
|
||||
#endif
|
||||
#if PM_NUM_MODES == 2
|
||||
#define PM_BLOCKER_INITIAL { 1, 0 }
|
||||
#endif
|
||||
#if PM_NUM_MODES == 3
|
||||
#define PM_BLOCKER_INITIAL { 1, 1, 0 }
|
||||
#endif
|
||||
#if PM_NUM_MODES == 4
|
||||
#define PM_BLOCKER_INITIAL { 1, 1, 1, 0 }
|
||||
#endif
|
||||
#if PM_NUM_MODES == 5
|
||||
#define PM_BLOCKER_INITIAL { 1, 1, 1, 1, 0 }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Global variable for keeping track of blocked modes
|
||||
*/
|
||||
static pm_blocker_t pm_blocker = { .val_u32 = PM_BLOCKER_INITIAL };
|
||||
static pm_blocker_t pm_blocker = { .blockers = PM_BLOCKER_INITIAL };
|
||||
|
||||
void pm_set_lowest(void)
|
||||
{
|
||||
pm_blocker_t blocker = { .val_u32 = atomic_load_u32(&pm_blocker.val_u32) };
|
||||
unsigned mode = PM_NUM_MODES;
|
||||
|
||||
/* set lowest mode if blocker is still the same */
|
||||
unsigned state = irq_disable();
|
||||
while (mode) {
|
||||
if (blocker.val_u8[mode-1]) {
|
||||
if (pm_blocker.blockers[mode - 1]) {
|
||||
break;
|
||||
}
|
||||
mode--;
|
||||
}
|
||||
|
||||
/* set lowest mode if blocker is still the same */
|
||||
unsigned state = irq_disable();
|
||||
if (blocker.val_u32 == pm_blocker.val_u32) {
|
||||
DEBUG("pm: setting mode %u\n", mode);
|
||||
if (mode != PM_NUM_MODES) {
|
||||
pm_set(mode);
|
||||
}
|
||||
else {
|
||||
DEBUG("pm: mode block changed\n");
|
||||
}
|
||||
irq_restore(state);
|
||||
}
|
||||
|
||||
void pm_block(unsigned mode)
|
||||
{
|
||||
assert(pm_blocker.val_u8[mode] != 255);
|
||||
assert(pm_blocker.blockers[mode] != 255);
|
||||
|
||||
unsigned state = irq_disable();
|
||||
pm_blocker.val_u8[mode]++;
|
||||
pm_blocker.blockers[mode]++;
|
||||
irq_restore(state);
|
||||
}
|
||||
|
||||
void pm_unblock(unsigned mode)
|
||||
{
|
||||
assert(pm_blocker.val_u8[mode] > 0);
|
||||
assert(pm_blocker.blockers[mode] > 0);
|
||||
|
||||
unsigned state = irq_disable();
|
||||
pm_blocker.val_u8[mode]--;
|
||||
pm_blocker.blockers[mode]--;
|
||||
irq_restore(state);
|
||||
}
|
||||
|
||||
pm_blocker_t pm_get_blocker(void)
|
||||
{
|
||||
pm_blocker_t result = { .val_u32 = atomic_load_u32(&pm_blocker.val_u32) };
|
||||
pm_blocker_t result;
|
||||
|
||||
unsigned state = irq_disable();
|
||||
memcpy(&result, &pm_blocker, sizeof(result));
|
||||
irq_restore(state);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -107,7 +107,7 @@ static int cmd_unblock(char *arg)
|
||||
}
|
||||
|
||||
pm_blocker_t pm_blocker = pm_get_blocker();
|
||||
if (pm_blocker.val_u8[mode] == 0) {
|
||||
if (pm_blocker.blockers[mode] == 0) {
|
||||
printf("Mode %d is already unblocked.\n", mode);
|
||||
return 1;
|
||||
}
|
||||
@ -127,8 +127,8 @@ static int cmd_show(char *arg)
|
||||
|
||||
pm_blocker_t pm_blocker = pm_get_blocker();
|
||||
for (unsigned i = 0; i < PM_NUM_MODES; i++) {
|
||||
printf("mode %u blockers: %u \n", i, pm_blocker.val_u8[i]);
|
||||
if (pm_blocker.val_u8[i]) {
|
||||
printf("mode %u blockers: %u \n", i, pm_blocker.blockers[i]);
|
||||
if (pm_blocker.blockers[i]) {
|
||||
lowest_allowed_mode = i + 1;
|
||||
}
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ static int cmd_unblock_rtc(int argc, char **argv)
|
||||
}
|
||||
|
||||
pm_blocker_t pm_blocker = pm_get_blocker();
|
||||
if (pm_blocker.val_u8[mode] == 0) {
|
||||
if (pm_blocker.blockers[mode] == 0) {
|
||||
printf("Mode %d is already unblocked.\n", mode);
|
||||
return 1;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user