1
0
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:
Oleg Hahm 2022-04-08 14:04:46 +02:00 committed by GitHub
commit f3ffe134b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 70 additions and 59 deletions

View File

@ -95,7 +95,7 @@ enum {
* @name Power management configuration
* @{
*/
#define PM_NUM_MODES (4)
#define PM_NUM_MODES (5)
/** @} */
/**

View File

@ -56,7 +56,7 @@ typedef uint32_t gpio_t;
* @name Power mode configuration
* @{
*/
#define PM_NUM_MODES (4)
#define PM_NUM_MODES (5)
/** @} */
/**

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -73,7 +73,7 @@ typedef enum {
/**
* @brief Power management configuration
*/
#define PM_NUM_MODES (2U)
#define PM_NUM_MODES (3U)
/**
* @brief UART device configuration

View File

@ -36,7 +36,7 @@ extern "C" {
* @name Power mode configuration
* @{
*/
#define PM_NUM_MODES (3)
#define PM_NUM_MODES (4)
/** @} */
/**

View File

@ -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
/**

View File

@ -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 */
/** @} */
/**

View File

@ -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
* @{

View File

@ -35,7 +35,7 @@ extern "C" {
* @name Power mode configuration
* @{
*/
#define PM_NUM_MODES (2)
#define PM_NUM_MODES (3)
/** @} */
/**

View File

@ -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

View File

@ -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:

View File

@ -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);

View File

@ -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;
/**

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}