diff --git a/cpu/stm32f1/cpu.c b/cpu/stm32f1/cpu.c index e30ef52e079ae21db322b74a18a7a1c1055fe07c..99b24be5c0e9fd3489f98ff4a49215ba3e5787de 100644 --- a/cpu/stm32f1/cpu.c +++ b/cpu/stm32f1/cpu.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2013 INRIA * Copyright (C) 2014 Freie Universität Berlin + * Copyright (C) 2016 TriaGnoSys GmbH * * 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 @@ -19,6 +20,7 @@ * @author Thomas Eichinger <thomas.eichinger@fu-berlin.de> * @author Hauke Petersen <hauke.petersen@fu-berlin.de> * @author Nick van IJzendoorn <nijzendoorn@engineering-spirit.nl> + * @author VÃctor Ariño <victor.arino@zii.aero> * * @} */ @@ -26,9 +28,19 @@ #include "cpu.h" #include "periph_conf.h" -/* Check the source to be used for the PLL */ +/* See if we want to use the PLL */ +#if defined(CLOCK_PLL_DIV) || defined(CLOCK_PLL_MUL) +#define CLOCK_USE_PLL 1 +#else +#define CLOCK_USE_PLL 0 +#endif + +/* Check the source to be used and parameters */ #if defined(CLOCK_HSI) && defined(CLOCK_HSE) #error "Only provide one of two CLOCK_HSI/CLOCK_HSE" +#elif (CLOCK_USE_PLL == 1) && (!defined(CLOCK_PLL_MUL) || !defined(CLOCK_PLL_DIV)) +#error "When using PLL both CLOCK_PLL_DIV and CLOCK_PLL_MUL must be provided" + #elif CLOCK_HSI #define CLOCK_CR_SOURCE RCC_CR_HSION #define CLOCK_CR_SOURCE_RDY RCC_CR_HSIRDY @@ -36,8 +48,11 @@ #define CLOCK_PLL_SOURCE 0 #define CLOCK_DISABLE_HSI 0 -#if (CLOCK_PLL_DIV != 1) -#error "HSI clock cannot be divided" +#if (CLOCK_USE_PLL == 0) +#define CLOCK_CFGR_SW RCC_CFGR_SW_HSI +#define CLOCK_CFGR_SW_RDY RCC_CFGR_SWS_HSI +#elif (CLOCK_PLL_DIV != 2) +#error "CLOCK_PLL_DIV can only be 2 for the HSI" #endif #elif CLOCK_HSE @@ -46,11 +61,14 @@ #define CLOCK_PLL_SOURCE RCC_CFGR_PLLSRC #define CLOCK_DISABLE_HSI 1 -#if (CLOCK_PLL_DIV == 2) +#if (CLOCK_USE_PLL == 0) +#define CLOCK_CFGR_SW RCC_CFGR_SW_HSE +#define CLOCK_CFGR_SW_RDY RCC_CFGR_SWS_HSE +#elif (CLOCK_PLL_DIV == 2) #define CLOCK_PLL_DIVMSK RCC_CFGR_PLLXTPRE #elif (CLOCK_PLL_DIV == 1) #define CLOCK_PLL_DIVMSK 0 -#else +#elif defined(CLOCK_PLL_DIV) #error "HSE divider must be 1 or 2" #endif @@ -58,11 +76,15 @@ #error "Please provide CLOCK_HSI or CLOCK_HSE in boards/NAME/includes/perhip_cpu.h" #endif +#if (CLOCK_USE_PLL == 1) +#define CLOCK_CFGR_SW RCC_CFGR_SW_PLL +#define CLOCK_CFGR_SW_RDY RCC_CFGR_SWS_PLL #if CLOCK_PLL_MUL > 16 #error "PLL multiplier cannot exceed 16 times" #elif CLOCK_PLL_MUL < 2 #error "PLL multiplier cannot be set to 1 or lower" #endif +#endif static void clk_init(void); @@ -110,18 +132,21 @@ static void clk_init(void) RCC->CFGR |= (uint32_t)CLOCK_APB2_DIV; /* PCLK1 = HCLK */ RCC->CFGR |= (uint32_t)CLOCK_APB1_DIV; + +#if (CLOCK_USE_PLL == 1) /* PLL configuration: PLLCLK = CLOCK_SOURCE / PLL_DIV * PLL_MUL */ - RCC->CFGR &= ~((uint32_t)(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL)); RCC->CFGR |= (uint32_t)(CLOCK_PLL_SOURCE | CLOCK_PLL_DIVMSK | ((CLOCK_PLL_MUL - 2) << 18)); /* Enable PLL */ RCC->CR |= RCC_CR_PLLON; /* Wait till PLL is ready */ while ((RCC->CR & RCC_CR_PLLRDY) == 0) {} - /* Select PLL as system clock source */ +#endif + + /* Select the system clock source */ RCC->CFGR &= ~((uint32_t)(RCC_CFGR_SW)); - RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; - /* Wait till PLL is used as system clock source */ - while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) {} + RCC->CFGR |= (uint32_t)CLOCK_CFGR_SW; + /* Wait till selected system clock source is ready */ + while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != CLOCK_CFGR_SW_RDY) {} #if CLOCK_DISABLE_HSI RCC->CR &= ~(RCC_CR_HSION); diff --git a/cpu/stm32f1/lpm_arch.c b/cpu/stm32f1/lpm_arch.c index e41810c880b95e4129febbd1475d0498f9467c44..fe329cb5622ce0cd63d71ad3b37c499b5462629c 100644 --- a/cpu/stm32f1/lpm_arch.c +++ b/cpu/stm32f1/lpm_arch.c @@ -1,6 +1,5 @@ /* - * Copyright (C) 2013 INRIA - * Copyright (C) 2014 Freie Universität Berlin + * Copyright (C) 2015 Engineering-Spirit * * 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 @@ -12,45 +11,88 @@ * @{ * * @file - * @brief Implementation of the kernel's lpm interface + * @brief Implementation of the kernels power management interface * - * @author Alaeddine Weslati <alaeddine.weslati@inria.fr> - * @author Hauke Petersen <hauke.petersen@fu-berlin.de> + * @author Nick v. IJzendoorn <nijzndoorn@engineering-spirit.nl> * * @} */ +#include "cpu.h" #include "arch/lpm_arch.h" +static enum lpm_mode current_mode = LPM_UNKNOWN; + void lpm_arch_init(void) { - /* TODO */ + current_mode = LPM_ON; } enum lpm_mode lpm_arch_set(enum lpm_mode target) { - (void) target; - /* TODO */ - return 0; + enum lpm_mode last_mode = current_mode; + + switch (target) { + case LPM_ON: /* STM Run mode */ + current_mode = LPM_ON; + break; + case LPM_IDLE: /* STM Sleep mode */ + current_mode = LPM_IDLE; + /* Reset SLEEPDEEP bit of system control block */ + SCB->SCR &= ~(SCB_SCR_SLEEPDEEP_Msk); + /* Enter sleep mode */ + __WFI(); + break; + case LPM_SLEEP: /* STM Stop mode */ + current_mode = LPM_SLEEP; + /* Clear PDDS and LPDS bits to enter stop mode on */ + /* deepsleep with voltage regulator on */ + PWR->CR &= ~(PWR_CR_PDDS | PWR_CR_LPDS); + /* Set SLEEPDEEP bit of system control block */ + SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; + /* Enter stop mode */ + __WFI(); + break; + case LPM_POWERDOWN: /* STM Standby mode */ + /* Fall-through */ + case LPM_OFF: /* STM Standby mode */ + current_mode = LPM_POWERDOWN; + /* Set PDDS to enter standby mode on deepsleep and clear flags */ + PWR->CR |= (PWR_CR_PDDS | PWR_CR_CWUF | PWR_CR_CSBF); + /* Enable WKUP pin to use for wakeup from standby mode */ + PWR->CSR |= PWR_CSR_EWUP; + /* Set SLEEPDEEP bit of system control block */ + SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; +#if defined ( __CC_ARM ) + /* Ensure that store operations are completed */ + __force_stores(); +#endif + /* Enter standby mode */ + __WFI(); + break; + default: + break; + } + + return last_mode; } enum lpm_mode lpm_arch_get(void) { - /* TODO */ - return 0; + return current_mode; } void lpm_arch_awake(void) { - /* TODO */ + if (current_mode == LPM_SLEEP) { + /* After stop mode, the clock system needs to be reconfigured */ + cpu_init(); + } + current_mode = LPM_ON; } -void lpm_arch_begin_awake(void) -{ - /* TODO */ -} +/** Not provided */ +inline void lpm_arch_begin_awake(void) { } -void lpm_arch_end_awake(void) -{ - /* TODO */ -} +/** Not provided */ +inline void lpm_arch_end_awake(void) { }