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

Merge pull request #16212 from nandojve/xmega_pm

cpu/atxmega: Add periph power management
This commit is contained in:
Marian Buschsieweke 2021-04-07 11:45:24 +02:00 committed by GitHub
commit ac774f3404
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 139 additions and 16 deletions

View File

@ -36,6 +36,7 @@ extern "C" {
static const timer_conf_t timer_config[] = {
{
.dev = (void *)&TCC1,
.pwr = PWR_RED_REG(PWR_PORT_C, PR_TC1_bm),
.type = TC_TYPE_1,
.int_lvl = { CPU_INT_LVL_LOW,
CPU_INT_LVL_OFF,
@ -44,6 +45,7 @@ static const timer_conf_t timer_config[] = {
},
{
.dev = (void *)&TCC0,
.pwr = PWR_RED_REG(PWR_PORT_C, PR_TC0_bm),
.type = TC_TYPE_0,
.int_lvl = { CPU_INT_LVL_LOW,
CPU_INT_LVL_LOW,
@ -69,6 +71,7 @@ static const timer_conf_t timer_config[] = {
static const uart_conf_t uart_config[] = {
{ /* CDC-ACM */
.dev = &USARTE0,
.pwr = PWR_RED_REG(PWR_PORT_E, PR_USART0_bm),
.rx_pin = GPIO_PIN(PORT_E, 2),
.tx_pin = GPIO_PIN(PORT_E, 3),
#ifdef MODULE_PERIPH_UART_HW_FC

View File

@ -22,6 +22,7 @@
#include "cpu.h"
#include "cpu_clock.h"
#include "cpu_pm.h"
#include "panic.h"
#define ENABLE_DEBUG 0
@ -63,18 +64,7 @@ void avr8_reset_cause(void)
void __attribute__((weak)) avr8_clk_init(void)
{
volatile uint8_t *reg = (uint8_t *)&PR.PRGEN;
uint8_t i;
/* Turn off all peripheral clocks that can be turned off. */
for (i = 0; i <= 7; i++) {
reg[i] = 0xff;
}
/* Turn on all peripheral clocks that can be turned on. */
for (i = 0; i <= 7; i++) {
reg[i] = 0x00;
}
pm_periph_power_off();
/* XMEGA A3U [DATASHEET] p.23 After reset, the device starts up running
* from the 2MHz internal oscillator. The other clock sources, DFLLs

View File

@ -0,0 +1,41 @@
/*
* Copyright (C) 2021 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_atxmega
* @{
*
* @file
* @brief Power Management and Power Reduction API
*
* This help to save power disabling all non used peripherals. It can help to
* save power when in active or sleep modes. For any other low power modes
* xmega will freeze all peripherals clock.
*
* @author Gerson Fernando Budke <nandojve@gmail.com>
*/
#include "periph_cpu.h"
#ifndef CPU_PM_H
#define CPU_PM_H
#ifdef __cplusplus
extern "C" {
#endif
void pm_periph_enable(pwr_reduction_t pwr);
void pm_periph_disable(pwr_reduction_t pwr);
void pm_periph_power_off(void);
#ifdef __cplusplus
}
#endif
#endif /* CPU_PM_H */
/** @} */

View File

@ -68,6 +68,29 @@ enum {
PORT_MAX,
};
/**
* @brief Power Reduction Peripheral Mask
*/
typedef uint16_t pwr_reduction_t;
/**
* @brief Define a CPU specific Power Reduction index macro
*/
#define PWR_RED_REG(reg, dev) ((reg << 8) | dev)
/**
* @brief Define a CPU specific Power Reduction index macro
*/
enum {
PWR_GENERAL_POWER,
PWR_PORT_A,
PWR_PORT_B,
PWR_PORT_C,
PWR_PORT_D,
PWR_PORT_E,
PWR_PORT_F,
};
/**
* @name Power management configuration
* @{
@ -190,6 +213,7 @@ typedef enum {
*/
typedef struct {
USART_t *dev; /**< pointer to the used UART device */
pwr_reduction_t pwr; /**< Power Management */
gpio_t rx_pin; /**< pin used for RX */
gpio_t tx_pin; /**< pin used for TX */
#ifdef MODULE_PERIPH_UART_HW_FC
@ -235,6 +259,7 @@ typedef enum {
*/
typedef struct {
TC0_t *dev; /**< Pointer to the used as Timer device */
pwr_reduction_t pwr; /**< Power Management */
timer_type_t type; /**< Timer Type */
cpu_int_lvl_t int_lvl[TIMER_CH_MAX_NUMOF]; /**< Interrupt channels level */
} timer_conf_t;

View File

@ -23,10 +23,41 @@
#include "periph_conf.h"
#include "periph/pm.h"
#include "cpu_pm.h"
#define ENABLE_DEBUG 0
#include "debug.h"
#define PWR_REG_BASE ((uint16_t)&PR)
#define PWR_REG_OFFSET (0x01)
/**
* @brief Extract the device id of the given power reduction mask
*/
static inline uint8_t _device_mask(pwr_reduction_t pwr)
{
return (pwr & 0xff);
}
/**
* @brief Extract the register id of the given power reduction mask
*/
static inline uint8_t _register_id(pwr_reduction_t pwr)
{
return (pwr >> 8) & 0xff;
}
/**
* @brief Generate the register index of the given power reduction mask
*/
static inline uint8_t *_register_addr(pwr_reduction_t pwr)
{
uint8_t id = _register_id(pwr);
uint16_t addr = PWR_REG_BASE + (id * PWR_REG_OFFSET);
return (uint8_t *)addr;
}
void pm_reboot(void)
{
DEBUG("Reboot Software Reset\n" );
@ -78,3 +109,30 @@ void pm_set(unsigned mode)
sleep_disable();
irq_restore(irq_state);
}
void pm_periph_enable(pwr_reduction_t pwr)
{
uint8_t mask = _device_mask(pwr);
uint8_t *reg = _register_addr(pwr);
*reg &= ~mask;
}
void pm_periph_disable(pwr_reduction_t pwr)
{
uint8_t mask = _device_mask(pwr);
uint8_t *reg = _register_addr(pwr);
*reg |= mask;
}
void pm_periph_power_off(void)
{
uint8_t *reg = _register_addr(PWR_GENERAL_POWER);
uint8_t i;
/* Freeze all peripheral clocks */
for (i = 0; i <= 7; i++) {
reg[i] = 0xff;
}
}

View File

@ -24,6 +24,7 @@
#include <assert.h>
#include "cpu.h"
#include "cpu_pm.h"
#include "thread.h"
#include "periph/timer.h"
@ -112,6 +113,8 @@ int timer_init(tim_t tim, unsigned long freq, timer_cb_t cb, void *arg)
return -1;
}
pm_periph_enable(timer_config[tim].pwr);
dev = timer_config[tim].dev;
/* stop and reset timer */
@ -301,6 +304,7 @@ void timer_stop(tim_t tim)
DEBUG("timer_stop\n");
timer_config[tim].dev->CTRLA = 0;
timer_config[tim].dev->CTRLFSET = TC_CMD_RESTART_gc;
pm_periph_disable(timer_config[tim].pwr);
}
void timer_start(tim_t tim)
@ -310,6 +314,7 @@ void timer_start(tim_t tim)
}
DEBUG("timer_start\n");
pm_periph_enable(timer_config[tim].pwr);
timer_config[tim].dev->CTRLA = ctx[tim].prescaler;
}

View File

@ -29,6 +29,7 @@
#include "board.h"
#include "cpu.h"
#include "cpu_pm.h"
#include "sched.h"
#include "thread.h"
#include "periph/uart.h"
@ -257,6 +258,8 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
isr_ctx[uart].rx_cb = rx_cb;
isr_ctx[uart].arg = arg;
pm_periph_enable(uart_config[uart].pwr);
/* disable and reset UART */
dev(uart)->CTRLA = 0;
dev(uart)->CTRLB = 0;
@ -315,14 +318,12 @@ void uart_write(uart_t uart, const uint8_t *data, size_t len)
void uart_poweron(uart_t uart)
{
(void)uart;
/* not implemented (yet) */
pm_periph_enable(uart_config[uart].pwr);
}
void uart_poweroff(uart_t uart)
{
(void)uart;
/* not implemented (yet) */
pm_periph_disable(uart_config[uart].pwr);
}
static inline void _rx_isr_handler(int num)