Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Tracking] kinetis: Implement low power modes #11789

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 14 additions & 11 deletions boards/common/kw41z/include/periph_conf_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,16 @@ static const clock_config_t clock_config = {
.count_ch = 1, \
}, \
}
#define LPTMR_NUMOF (1U)
#define LPTMR_CONFIG { \
{ \
.dev = LPTMR0, \
.irqn = LPTMR0_IRQn, \
.src = 2, \
.base_freq = 32768u, \
} \
}
#define LPTMR_NUMOF (1U)
#define LPTMR_CONFIG { \
{ \
.dev = LPTMR0, \
.irqn = LPTMR0_IRQn, \
.base_freq = 32768u, \
.src = 2, \
.llwu = LLWU_WAKEUP_MODULE_LPTMR0, \
}, \
}
#define TIMER_NUMOF ((PIT_NUMOF) + (LPTMR_NUMOF))
#define PIT_BASECLOCK (CLOCK_BUSCLOCK)
#define LPTMR_ISR_0 isr_lptmr0
Expand All @@ -118,8 +119,10 @@ static const uart_conf_t uart_config[] = {
};
#define UART_NUMOF ARRAY_SIZE(uart_config)
#define LPUART_0_ISR isr_lpuart0
/* Use MCGIRCLK (internal reference 4 MHz clock) */
#define LPUART_0_SRC 3
/* Use MCGIRCLK (4 MHz internal reference - not available <= KINETIS_PM_LLS) */
#define LPUART_0_SRC 3
#define UART_CLOCK_PM_BLOCKER KINETIS_PM_LLS
#define UART_MAX_UNCLOCKED_BAUDRATE 19200ul
/** @} */

/**
Expand Down
17 changes: 9 additions & 8 deletions boards/frdm-k22f/include/periph_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,15 @@ static const clock_config_t clock_config = {
.count_ch = 3, \
}, \
}
#define LPTMR_NUMOF (1U)
#define LPTMR_CONFIG { \
{ \
.dev = LPTMR0, \
.irqn = LPTMR0_IRQn, \
.src = 2, \
.base_freq = 32768u, \
}, \
#define LPTMR_NUMOF (1U)
#define LPTMR_CONFIG { \
{ \
.dev = LPTMR0, \
.irqn = LPTMR0_IRQn, \
.base_freq = 32768u, \
.src = 2, \
.llwu = LLWU_WAKEUP_MODULE_LPTMR0, \
}, \
}
#define TIMER_NUMOF ((PIT_NUMOF) + (LPTMR_NUMOF))

Expand Down
17 changes: 9 additions & 8 deletions boards/frdm-k64f/include/periph_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,15 @@ static const clock_config_t clock_config = {
.count_ch = 3, \
}, \
}
#define LPTMR_NUMOF (1U)
#define LPTMR_CONFIG { \
{ \
.dev = LPTMR0, \
.irqn = LPTMR0_IRQn, \
.src = 2, \
.base_freq = 32768u, \
}, \
#define LPTMR_NUMOF (1U)
#define LPTMR_CONFIG { \
{ \
.dev = LPTMR0, \
.irqn = LPTMR0_IRQn, \
.base_freq = 32768u, \
.src = 2, \
.llwu = LLWU_WAKEUP_MODULE_LPTMR0, \
}, \
}
#define TIMER_NUMOF ((PIT_NUMOF) + (LPTMR_NUMOF))

Expand Down
19 changes: 10 additions & 9 deletions boards/mulle/include/periph_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,15 +102,16 @@ static const clock_config_t clock_config = {
.count_ch = 3, \
}, \
}
#define LPTMR_NUMOF (1U)
#define LPTMR_CONFIG { \
{ \
.dev = LPTMR0, \
.irqn = LPTMR0_IRQn, \
.src = 2, \
.base_freq = 32768u, \
} \
}
#define LPTMR_NUMOF (1U)
#define LPTMR_CONFIG { \
{ \
.dev = LPTMR0, \
.irqn = LPTMR0_IRQn, \
.base_freq = 32768u, \
.src = 2, \
.llwu = LLWU_WAKEUP_MODULE_LPTMR0, \
}, \
}
#define TIMER_NUMOF ((PIT_NUMOF) + (LPTMR_NUMOF))

#define PIT_BASECLOCK (CLOCK_BUSCLOCK)
Expand Down
3 changes: 0 additions & 3 deletions boards/openlabs-kw41z-mini/include/periph_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,6 @@ static const uart_conf_t uart_config[] = {
.scgc_bit = SIM_SCGC5_LPUART0_SHIFT,
.mode = UART_MODE_8N1,
.type = KINETIS_LPUART,
#ifdef MODULE_PERIPH_LLWU /* TODO remove ifdef after #11789 is merged */
.llwu_rx = LLWU_WAKEUP_PIN_PTC6,
#endif
},
};
#define UART_NUMOF ARRAY_SIZE(uart_config)
Expand Down
4 changes: 4 additions & 0 deletions cpu/kinetis/Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ else ifneq (,$(filter periph_mcg,$(FEATURES_USED)))
USEMODULE += periph_mcg
endif

USEMODULE += periph_llwu
USEMODULE += periph_wdog
USEMODULE += pm_layered

include $(RIOTCPU)/cortexm_common/Makefile.dep
ifneq (,$(filter periph_uart,$(USEMODULE)))
FEATURES_OPTIONAL += periph_gpio_irq
endif
1 change: 1 addition & 0 deletions cpu/kinetis/Makefile.features
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ ifneq (,$(filter-out $(_KINETIS_CPU_MODELS_WITHOUT_HWRNG),$(CPU_MODEL)))
FEATURES_PROVIDED += periph_hwrng
endif

FEATURES_PROVIDED += periph_llwu
FEATURES_PROVIDED += periph_gpio
FEATURES_PROVIDED += periph_gpio_irq

Expand Down
14 changes: 14 additions & 0 deletions cpu/kinetis/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@
#ifdef MODULE_PERIPH_MCG
#include "mcg.h"
#endif
#if defined(MODULE_PERIPH_LLWU)
#include "llwu.h"
#elif defined(MODULE_PM_LAYERED)
#include "pm_layered.h"
#endif

/**
* @brief Initialize the CPU, set IRQ priorities
Expand All @@ -46,6 +51,15 @@ void cpu_init(void)
/* initialize stdio prior to periph_init() to allow use of DEBUG() there */
stdio_init();

#if defined(MODULE_PERIPH_LLWU)
/* initialize the LLWU module for sleep/wakeup management */
llwu_init();
#elif defined(MODULE_PM_LAYERED)
/* Block LLS mode since we are not using the LLWU module, which is required
* to be able to wake up from LLS */
pm_block(KINETIS_PM_LLS);
#endif

/* trigger static peripheral initialization */
periph_init();
}
139 changes: 139 additions & 0 deletions cpu/kinetis/include/cpu_conf_kinetis.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,145 @@ extern "C"
#define PIN_INTERRUPT_EDGE 0b1011
/** @} */

/**
* @brief Mapping internal module interrupts to LLWU wake up sources
*
* @note Modules not listed here CAN NOT be used to wake the CPU from LLS or
* VLLSx power modes.
*
* The numbers are hardware specific, but have the same values across all the
* supported Kinetis CPUs
*/
typedef enum llwu_wakeup_module {
LLWU_WAKEUP_MODULE_LPTMR0 = 0,
LLWU_WAKEUP_MODULE_CMP0 = 1,
LLWU_WAKEUP_MODULE_RADIO = 2, /* KWx1Z devices */
LLWU_WAKEUP_MODULE_CMP1 = 2, /* others */
LLWU_WAKEUP_MODULE_DCDC = 3, /* KWx1Z devices */
LLWU_WAKEUP_MODULE_CMP2 = 3, /* others */
LLWU_WAKEUP_MODULE_TSI = 4,
LLWU_WAKEUP_MODULE_RTC_ALARM = 5,
LLWU_WAKEUP_MODULE_RESERVED = 6,
LLWU_WAKEUP_MODULE_RTC_SECONDS = 7,
LLWU_WAKEUP_MODULE_NUMOF
} llwu_wakeup_module_t;

/**
* @brief Mapping LLWU wakeup pin sources to PORT interrupt numbers
*/
typedef struct {
PORT_Type *port; /**< PORT register */
uint32_t isfr_mask; /**< ISFR bitmask */
} llwu_wakeup_pin_to_port_t;

/**
* @brief Mapping physical pins to LLWU wakeup pin source numbers
*
* @note Pins not listed here CAN NOT be used to wake the CPU from LLS or
* VLLSx power modes.
*
* The numbers are hardware specific, but have the same values across all the
* supported Kinetis CPUs.
*/
#if defined(KINETIS_SERIES_W) && defined(KINETIS_CORE_Z) && (KINETIS_SUBFAMILY == 1)
/* KW41Z has different LLWU pins */
typedef enum llwu_wakeup_pin {
LLWU_WAKEUP_PIN_PTC16 = 0,
LLWU_WAKEUP_PIN_PTC17 = 1,
LLWU_WAKEUP_PIN_PTC18 = 2,
LLWU_WAKEUP_PIN_PTC19 = 3,
LLWU_WAKEUP_PIN_PTA16 = 4,
LLWU_WAKEUP_PIN_PTA17 = 5,
LLWU_WAKEUP_PIN_PTA18 = 6,
LLWU_WAKEUP_PIN_PTA19 = 7,
LLWU_WAKEUP_PIN_PTB0 = 8,
LLWU_WAKEUP_PIN_PTC0 = 9,
LLWU_WAKEUP_PIN_PTC2 = 10,
LLWU_WAKEUP_PIN_PTC3 = 11,
LLWU_WAKEUP_PIN_PTC4 = 12,
LLWU_WAKEUP_PIN_PTC5 = 13,
LLWU_WAKEUP_PIN_PTC6 = 14,
LLWU_WAKEUP_PIN_PTC7 = 15,
LLWU_WAKEUP_PIN_NUMOF,
LLWU_WAKEUP_PIN_UNDEF
} llwu_wakeup_pin_t;

/**
* @brief Mapping LLWU wakeup pin number to PORT module interrupt flags
*/
static const llwu_wakeup_pin_to_port_t llwu_wakeup_pin_to_port[LLWU_WAKEUP_PIN_NUMOF] = {
[LLWU_WAKEUP_PIN_PTC16] = { .port = PORTC, .isfr_mask = (1u << 16), },
[LLWU_WAKEUP_PIN_PTC17] = { .port = PORTC, .isfr_mask = (1u << 17), },
[LLWU_WAKEUP_PIN_PTC18] = { .port = PORTC, .isfr_mask = (1u << 18), },
[LLWU_WAKEUP_PIN_PTC19] = { .port = PORTC, .isfr_mask = (1u << 19), },
[LLWU_WAKEUP_PIN_PTA16] = { .port = PORTA, .isfr_mask = (1u << 16), },
[LLWU_WAKEUP_PIN_PTA17] = { .port = PORTA, .isfr_mask = (1u << 17), },
[LLWU_WAKEUP_PIN_PTA18] = { .port = PORTA, .isfr_mask = (1u << 18), },
[LLWU_WAKEUP_PIN_PTA19] = { .port = PORTA, .isfr_mask = (1u << 19), },
[LLWU_WAKEUP_PIN_PTB0 ] = { .port = PORTB, .isfr_mask = (1u << 0), },
[LLWU_WAKEUP_PIN_PTC0 ] = { .port = PORTC, .isfr_mask = (1u << 0), },
[LLWU_WAKEUP_PIN_PTC2 ] = { .port = PORTC, .isfr_mask = (1u << 2), },
[LLWU_WAKEUP_PIN_PTC3 ] = { .port = PORTC, .isfr_mask = (1u << 3), },
[LLWU_WAKEUP_PIN_PTC4 ] = { .port = PORTC, .isfr_mask = (1u << 4), },
[LLWU_WAKEUP_PIN_PTC5 ] = { .port = PORTC, .isfr_mask = (1u << 5), },
[LLWU_WAKEUP_PIN_PTC6 ] = { .port = PORTC, .isfr_mask = (1u << 6), },
[LLWU_WAKEUP_PIN_PTC7 ] = { .port = PORTC, .isfr_mask = (1u << 7), },
};
#else
typedef enum llwu_wakeup_pin {
LLWU_WAKEUP_PIN_PTE1 = 0,
LLWU_WAKEUP_PIN_PTE2 = 1,
LLWU_WAKEUP_PIN_PTE4 = 2,
LLWU_WAKEUP_PIN_PTA4 = 3,
LLWU_WAKEUP_PIN_PTA13 = 4,
LLWU_WAKEUP_PIN_PTB0 = 5,
LLWU_WAKEUP_PIN_PTC1 = 6,
LLWU_WAKEUP_PIN_PTC3 = 7,
LLWU_WAKEUP_PIN_PTC4 = 8,
LLWU_WAKEUP_PIN_PTC5 = 9,
LLWU_WAKEUP_PIN_PTC6 = 10,
LLWU_WAKEUP_PIN_PTC11 = 11,
LLWU_WAKEUP_PIN_PTD0 = 12,
LLWU_WAKEUP_PIN_PTD2 = 13,
LLWU_WAKEUP_PIN_PTD4 = 14,
LLWU_WAKEUP_PIN_PTD6 = 15,
LLWU_WAKEUP_PIN_NUMOF,
LLWU_WAKEUP_PIN_UNDEF
} llwu_wakeup_pin_t;

/**
* @brief Mapping LLWU wakeup pin number to PORT module interrupt flags
*/
static const llwu_wakeup_pin_to_port_t llwu_wakeup_pin_to_port[LLWU_WAKEUP_PIN_NUMOF] = {
[LLWU_WAKEUP_PIN_PTE1 ] = { .port = PORTE, .isfr_mask = (1u << 1), },
[LLWU_WAKEUP_PIN_PTE2 ] = { .port = PORTE, .isfr_mask = (1u << 2), },
[LLWU_WAKEUP_PIN_PTE4 ] = { .port = PORTE, .isfr_mask = (1u << 4), },
[LLWU_WAKEUP_PIN_PTA4 ] = { .port = PORTA, .isfr_mask = (1u << 4), },
[LLWU_WAKEUP_PIN_PTA13] = { .port = PORTA, .isfr_mask = (1u << 13), },
[LLWU_WAKEUP_PIN_PTB0 ] = { .port = PORTB, .isfr_mask = (1u << 0), },
[LLWU_WAKEUP_PIN_PTC1 ] = { .port = PORTC, .isfr_mask = (1u << 1), },
[LLWU_WAKEUP_PIN_PTC3 ] = { .port = PORTC, .isfr_mask = (1u << 3), },
[LLWU_WAKEUP_PIN_PTC4 ] = { .port = PORTC, .isfr_mask = (1u << 4), },
[LLWU_WAKEUP_PIN_PTC5 ] = { .port = PORTC, .isfr_mask = (1u << 5), },
[LLWU_WAKEUP_PIN_PTC6 ] = { .port = PORTC, .isfr_mask = (1u << 6), },
[LLWU_WAKEUP_PIN_PTC11] = { .port = PORTC, .isfr_mask = (1u << 11), },
[LLWU_WAKEUP_PIN_PTD0 ] = { .port = PORTD, .isfr_mask = (1u << 0), },
[LLWU_WAKEUP_PIN_PTD2 ] = { .port = PORTD, .isfr_mask = (1u << 2), },
[LLWU_WAKEUP_PIN_PTD4 ] = { .port = PORTD, .isfr_mask = (1u << 4), },
[LLWU_WAKEUP_PIN_PTD6 ] = { .port = PORTD, .isfr_mask = (1u << 6), },
};
#endif

/**
* @brief LLWU wakeup pin edge settings
*/
typedef enum llwu_wakeup_edge {
LLWU_WAKEUP_EDGE_NONE = 0,
LLWU_WAKEUP_EDGE_RISING = 1,
LLWU_WAKEUP_EDGE_FALLING = 2,
LLWU_WAKEUP_EDGE_BOTH = 3,
} llwu_wakeup_edge_t;

/**
* @name Compatibility definitions between vendor headers
* @{
Expand Down
79 changes: 79 additions & 0 deletions cpu/kinetis/include/llwu.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright (C) 2017 SKF AB
*
* 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.
*/

/**
* @defgroup cpu_kinetis_llwu Kinetis LLWU
* @ingroup cpu_kinetis
* @brief Kinetis low leakage wakeup unit (LLWU) driver

* @{
*
* @file
* @brief Interface definition for the Kinetis LLWU driver.
*
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
*/

#ifndef LLWU_H
#define LLWU_H

#include "cpu.h"
#include "bit.h"
#include "periph_conf.h"
#include "periph/gpio.h"

#ifdef __cplusplus
extern "C"
{
#endif

/**
* @brief Initialize the Low-Leakage Wake Up (LLWU) hardware module
*/
void llwu_init(void);

/**
* @brief Enable a wakeup module in the LLWU
*/
inline static void llwu_wakeup_module_enable(llwu_wakeup_module_t mod)
{
assert(mod < LLWU_WAKEUP_MODULE_NUMOF);
bit_set8(&LLWU->ME, mod);
}

/**
* @brief Disable a wakeup module in the LLWU
*/
inline static void llwu_wakeup_module_disable(llwu_wakeup_module_t mod)
{
assert(mod < LLWU_WAKEUP_MODULE_NUMOF);
bit_clear8(&LLWU->ME, mod);
}

/**
* @brief Set the mode for a wakeup pin in the LLWU
*
* If @p cb is NULL when the pin edge is detected, the CPU will wake up for a
* few cycles which can allow other hardware modules to detect other interrupts.
* This may be particularily useful when using the wakeup pin for communication
* functions such as UART RX etc.
*
* @param[in] pin The pin to modify
* @param[in] edge Edge detection setting (rising, falling, both, none)
* @param[in] cb Callback function to execute when woken with this pin
* @param[in] arg Argument that will be passed to the callback
*/
void llwu_wakeup_pin_set(llwu_wakeup_pin_t pin, llwu_wakeup_edge_t edge, gpio_cb_t cb, void *arg);

#ifdef __cplusplus
}
#endif

/** @} */

#endif /* LLWU_H */
Loading