1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

cpu/gdv32: add pm_layered support

This commit is contained in:
Gunar Schorcht 2023-01-23 23:19:38 +01:00
parent b02ffb21b8
commit cfbda4022a
10 changed files with 116 additions and 6 deletions

View File

@ -22,7 +22,9 @@ config CPU_FAM_GD32V
select MODULE_PERIPH_CLIC if TEST_KCONFIG
select MODULE_PERIPH_WDT if MODULE_PERIPH_PM && HAS_PERIPH_WDT
select PACKAGE_NUCLEI_SDK
select PACKAGE_NMSIS_SDK
menu "GD32V configuration"
config CPU_MODEL_GD32VF103VBT6
bool
@ -48,4 +50,6 @@ config CPU_CORE
rsource "periph/Kconfig"
endmenu
source "$(RIOTCPU)/riscv_common/Kconfig"

View File

@ -0,0 +1 @@
DEFAULT_MODULE += pm_layered

View File

@ -12,3 +12,9 @@ FEATURES_PROVIDED += periph_flashpage_in_address_space
FEATURES_PROVIDED += periph_flashpage_pagewise
include $(RIOTCPU)/riscv_common/Makefile.features
# This configuration enables modules that are only available when using Kconfig
# module modelling
ifeq (1, $(TEST_KCONFIG))
KCONFIG_ADD_CONFIG += $(RIOTCPU)/gd32v/gd32v.config
endif

View File

@ -29,6 +29,8 @@ extern void __libc_init_array(void);
void cpu_init(void)
{
gd32vf103_clock_init();
/* enable PMU required for pm_layered */
periph_clk_en(APB1, RCU_APB1EN_PMUEN_Msk);
/* Common RISC-V initialization */
riscv_init();
early_init();

1
cpu/gd32v/gd32v.config Normal file
View File

@ -0,0 +1 @@
CONFIG_MODULE_PM_LAYERED=y

View File

@ -33,7 +33,39 @@ extern "C" {
* @name Power management configuration
* @{
*/
#define PROVIDES_PM_SET_LOWEST
/**
* @brief Number of usable low power modes
*/
#define PM_NUM_MODES (3U) /**< Number of usable low power modes */
/**
* @brief Power modes
*
* The GD32V has three power modes (terminology as defined by GigaDevice).
* - Sleep: Only the clock of the RISC-V core is switched off.
* - Deep sleep: The RISC-V core including all AHB and APB peripheralsa and all
* high speed clocks are off. The LDO is in operation and the
* SRAM is retained.
* The MCU can be woken up by external interrupts or events
* without restart.
* - Standby: The RISC-V core including all AHB and APB peripherals, all
* high-speed clocks, and the LDO are off. The SRAM is not
* retained.
* The MCU can be woken up by WKUP or the NRST pin, watchdog
* reset and RTC alarms with restart.
*/
enum {
GD32V_PM_STANDBY = 0, /**< STANDBY mode, */
GD32V_PM_DEEPSLEEP = 1, /**< DEEPSLEEP mode, corresponds to STOP mode of STM32 */
GD32V_PM_IDLE = 2 /**< IDLE mode */
};
/**
* @brief Wake-up pin used
*/
#ifndef CONFIG_PM_EWUP_USED
#define CONFIG_PM_EWUP_USED (0U)
#endif
/** @} */
/**

View File

@ -8,3 +8,9 @@
config MODULE_PERIPH
bool
default y
config PM_EWUP_USED
bool "Use PA0/WKUP pin"
depends on MODULE_PM_LAYERED
help
If enabled, the PA0/WKUP pin can be used to wake up the MCU from standby mode.

View File

@ -1,5 +1,6 @@
/*
* Copyright 2020 Koen Zandberg
* 2023 Gunar Schorcht
*
* 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
@ -13,16 +14,67 @@
* @brief Implementation of the CPU power management for Gigadevice GD32V
*
* @author Koen Zandberg <koen@bergzand.net>
* @author Gunar Schorcht <gunar@schorcht.net>
* @}
*/
#include <stdint.h>
#include <stdio.h>
#include "periph/pm.h"
#include "periph/wdt.h"
void pm_set_lowest(void)
#undef MCAUSE_CAUSE /* redefined in NMSIS header */
#include "core_feature_base.h"
void pm_set(unsigned mode)
{
__asm__ volatile ("wfi");
bool csr_deepsleep = false; /* RISC-V sleep mode */
switch (mode) {
case GD32V_PM_STANDBY:
csr_deepsleep = true;
/* set the STANDBY mode flag */
PMU->CTL |= PMU_CTL_WURST_Msk;
/* reset the wake up flag */
PMU->CTL |= PMU_CTL_STBMOD_Msk;
break;
case GD32V_PM_DEEPSLEEP:
csr_deepsleep = true;
/* reset the STANDBY mode flag */
PMU->CTL &= ~PMU_CTL_STBMOD_Msk;
/* use LDO low powered in deep sleep mode */
PMU->CTL |= PMU_CTL_LDOLP_Msk;
break;
case GD32V_PM_IDLE:
csr_deepsleep = false;
break;
default:
break;
}
if (csr_deepsleep) {
/* Enable WKUP pin if used */
PMU->CS &= ~PMU_CS_WUPEN_Msk;
PMU->CS |= (CONFIG_PM_EWUP_USED) ? PMU_CS_WUPEN_Msk : 0;
/* set CSR_SLEEPVALUE bit in RISC-V system control register */
__set_wfi_sleepmode(WFI_DEEP_SLEEP);
}
else {
/* clear CSR_SLEEPVALUE bit in RISC-V system control register */
__set_wfi_sleepmode(WFI_SHALLOW_SLEEP);
}
/* trigger sleeping, TODO wait for wake up event (__WFE) implementation */
__WFI();
if (csr_deepsleep) {
/* clear CSR_SLEEPVALUE bit in RISC-V system control register */
__set_wfi_sleepmode(WFI_SHALLOW_SLEEP);
/* after deep sleep, the IRC8M is used as clock so that a clock
* reinitialization is required */
gd32vf103_clock_init();
}
}
void pm_reboot(void)

View File

@ -22,6 +22,7 @@
#include "periph_cpu.h"
#include "cpu.h"
#include "clic.h"
#include "pm_layered.h"
#define RXENABLE (USART_CTL0_REN_Msk | USART_CTL0_RBNEIE_Msk)
@ -56,14 +57,18 @@ static inline void uart_init_pins(uart_t uart, uart_rx_cb_t rx_cb)
static inline void uart_enable_clock(uart_t uart)
{
/* TODO: add pm blocker */
if (isr_ctx[uart].rx_cb) {
pm_block(GD32V_PM_DEEPSLEEP);
}
periph_clk_en(uart_config[uart].bus, uart_config[uart].rcu_mask);
}
static inline void uart_disable_clock(uart_t uart)
{
periph_clk_dis(uart_config[uart].bus, uart_config[uart].rcu_mask);
/* TODO remove pm blocker */
if (isr_ctx[uart].rx_cb) {
pm_unblock(GD32V_PM_DEEPSLEEP);
}
}
static inline void uart_init_usart(uart_t uart, uint32_t baudrate)

View File

@ -55,6 +55,7 @@ rsource "mynewt-core/Kconfig"
rsource "nanocbor/Kconfig"
rsource "nanopb/Kconfig"
rsource "nanors/Kconfig"
rsource "nmsis_sdk/Kconfig"
rsource "nrfx/Kconfig"
rsource "qcbor/Kconfig"
rsource "qdsa/Kconfig"