mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-17 05:12:57 +01:00
cpu/atxmega: Add periph power management
The current xmega don't have a way to disable peripherals that are not in used. Add peripheral management to allow enable only the mcu blocks that will be used by application. This saves power on active and sleep modes. By default, at clock initialization, all peripherals are now disabled and each drive must activate at initialization phase. The periph_timer and periph_uart were updated with this new feature. Signed-off-by: Gerson Fernando Budke <nandojve@gmail.com>
This commit is contained in:
parent
e04dd4dcce
commit
93ed3cd9d6
@ -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
|
||||
|
41
cpu/atxmega/include/cpu_pm.h
Normal file
41
cpu/atxmega/include/cpu_pm.h
Normal 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 */
|
||||
/** @} */
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user