/* mbed Microcontroller Library ******************************************************************************* * Copyright (c) 2016, MultiTech Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. Neither the name of MultiTech nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************* */ #include "mtqn_low_power.h" #include "stdio.h" #include "mbed_debug.h" static uint32_t portA[6]; static uint32_t portB[6]; static uint32_t portC[6]; static uint32_t portD[6]; static uint32_t portE[6]; static uint32_t portF[6]; static uint32_t portG[6]; static uint32_t portH[6]; void mtqn_disable_systick_int() { SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk; } void mtqn_enable_systick_int() { SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk; } void mtqn_save_gpio_state() { portA[0] = GPIOA->MODER; portA[1] = GPIOA->OTYPER; portA[2] = GPIOA->OSPEEDR; portA[3] = GPIOA->PUPDR; portA[4] = GPIOA->AFR[0]; portA[5] = GPIOA->AFR[1]; portB[0] = GPIOB->MODER; portB[1] = GPIOB->OTYPER; portB[2] = GPIOB->OSPEEDR; portB[3] = GPIOB->PUPDR; portB[4] = GPIOB->AFR[0]; portB[5] = GPIOB->AFR[1]; portC[0] = GPIOC->MODER; portC[1] = GPIOC->OTYPER; portC[2] = GPIOC->OSPEEDR; portC[3] = GPIOC->PUPDR; portC[4] = GPIOC->AFR[0]; portC[5] = GPIOC->AFR[1]; portD[0] = GPIOD->MODER; portD[1] = GPIOD->OTYPER; portD[2] = GPIOD->OSPEEDR; portD[3] = GPIOD->PUPDR; portD[4] = GPIOD->AFR[0]; portD[5] = GPIOD->AFR[1]; portD[0] = GPIOD->MODER; portD[1] = GPIOD->OTYPER; portD[2] = GPIOD->OSPEEDR; portD[3] = GPIOD->PUPDR; portD[4] = GPIOD->AFR[0]; portD[5] = GPIOD->AFR[1]; portE[0] = GPIOE->MODER; portE[1] = GPIOE->OTYPER; portE[2] = GPIOE->OSPEEDR; portE[3] = GPIOE->PUPDR; portE[4] = GPIOE->AFR[0]; portE[5] = GPIOE->AFR[1]; portF[0] = GPIOF->MODER; portF[1] = GPIOF->OTYPER; portF[2] = GPIOF->OSPEEDR; portF[3] = GPIOF->PUPDR; portF[4] = GPIOF->AFR[0]; portF[5] = GPIOF->AFR[1]; portG[0] = GPIOG->MODER; portG[1] = GPIOG->OTYPER; portG[2] = GPIOG->OSPEEDR; portG[3] = GPIOG->PUPDR; portG[4] = GPIOG->AFR[0]; portG[5] = GPIOG->AFR[1]; portH[0] = GPIOH->MODER; portH[1] = GPIOH->OTYPER; portH[2] = GPIOH->OSPEEDR; portH[3] = GPIOH->PUPDR; portH[4] = GPIOH->AFR[0]; portH[5] = GPIOH->AFR[1]; } void mtqn_restore_gpio_state() { GPIOA->MODER = portA[0]; GPIOA->OTYPER = portA[1]; GPIOA->OSPEEDR = portA[2]; GPIOA->PUPDR = portA[3]; GPIOA->AFR[0] = portA[4]; GPIOA->AFR[1] = portA[5]; GPIOB->MODER = portB[0]; GPIOB->OTYPER = portB[1]; GPIOB->OSPEEDR = portB[2]; GPIOB->PUPDR = portB[3]; GPIOB->AFR[0] = portB[4]; GPIOB->AFR[1] = portB[5]; GPIOC->MODER = portC[0]; GPIOC->OTYPER = portC[1]; GPIOC->OSPEEDR = portC[2]; GPIOC->PUPDR = portC[3]; GPIOC->AFR[0] = portC[4]; GPIOC->AFR[1] = portC[5]; GPIOD->MODER = portD[0]; GPIOD->OTYPER = portD[1]; GPIOD->OSPEEDR = portD[2]; GPIOD->PUPDR = portD[3]; GPIOD->AFR[0] = portD[4]; GPIOD->AFR[1] = portD[5]; GPIOE->MODER = portE[0]; GPIOE->OTYPER = portE[1]; GPIOE->OSPEEDR = portE[2]; GPIOE->PUPDR = portE[3]; GPIOE->AFR[0] = portE[4]; GPIOE->AFR[1] = portE[5]; GPIOF->MODER = portF[0]; GPIOF->OTYPER = portF[1]; GPIOF->OSPEEDR = portF[2]; GPIOF->PUPDR = portF[3]; GPIOF->AFR[0] = portF[4]; GPIOF->AFR[1] = portF[5]; GPIOG->MODER = portG[0]; GPIOG->OTYPER = portG[1]; GPIOG->OSPEEDR = portG[2]; GPIOG->PUPDR = portG[3]; GPIOG->AFR[0] = portG[4]; GPIOG->AFR[1] = portG[5]; GPIOH->MODER = portH[0]; GPIOH->OTYPER = portH[1]; GPIOH->OSPEEDR = portH[2]; GPIOH->PUPDR = portH[3]; GPIOH->AFR[0] = portH[4]; GPIOH->AFR[1] = portH[5]; } /** * @brief System Clock Speed decrease * The system Clock source is shifted from HSI to MSI * while at the same time, MSI range is set to RCC_MSIRANGE_0 * to go down to 100 KHz * @param None * @retval None */ int SystemClock_Decrease(void) { RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_OscInitTypeDef RCC_OscInitStruct = {0}; /* MSI is enabled in range 0 (100Khz) */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI; RCC_OscInitStruct.MSIState = RCC_MSI_ON; RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_0; RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { /* Initialization Error */ return -1; } /* Select MSI as system clock source and keep HCLK, PCLK1 and PCLK2 clocks dividers as before */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI; if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) { /* Initialization Error */ return -1; } /* Disable HSI to reduce power consumption since MSI is used from that point */ __HAL_RCC_HSI_DISABLE(); __HAL_RCC_LSI_DISABLE(); return 0; } void mtqn_pull_up_pins(){ GPIO_InitTypeDef GPIO_InitStruct; HAL_PWREx_EnablePullUpPullDownConfig(); /* Enable GPIOs clock */ __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); __HAL_RCC_GPIOH_CLK_ENABLE(); __HAL_RCC_GPIOE_CLK_ENABLE(); __HAL_RCC_GPIOF_CLK_ENABLE(); __HAL_RCC_GPIOG_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_All ; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_All ; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_All ; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_All ; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_All ; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_All ; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOF, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_All ; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); /* Disable GPIOs clock */ __HAL_RCC_GPIOA_CLK_DISABLE(); __HAL_RCC_GPIOB_CLK_DISABLE(); __HAL_RCC_GPIOC_CLK_DISABLE(); __HAL_RCC_GPIOD_CLK_DISABLE(); __HAL_RCC_GPIOH_CLK_DISABLE(); __HAL_RCC_GPIOE_CLK_DISABLE(); __HAL_RCC_GPIOF_CLK_DISABLE(); __HAL_RCC_GPIOG_CLK_DISABLE(); } void mtqn_pull_down_pins(){ GPIO_InitTypeDef GPIO_InitStruct; HAL_PWREx_EnablePullUpPullDownConfig(); /* Enable GPIOs clock */ __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); __HAL_RCC_GPIOH_CLK_ENABLE(); __HAL_RCC_GPIOE_CLK_ENABLE(); __HAL_RCC_GPIOF_CLK_ENABLE(); __HAL_RCC_GPIOG_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_All ; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_PULLDOWN; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_All ; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_PULLDOWN; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_All ; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_PULLDOWN; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_All ; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_PULLDOWN; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_All ; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_PULLDOWN; HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_All ; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_PULLDOWN; HAL_GPIO_Init(GPIOF, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_All ; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_PULLDOWN; HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); /* Disable GPIOs clock */ __HAL_RCC_GPIOA_CLK_DISABLE(); __HAL_RCC_GPIOB_CLK_DISABLE(); __HAL_RCC_GPIOC_CLK_DISABLE(); __HAL_RCC_GPIOD_CLK_DISABLE(); __HAL_RCC_GPIOH_CLK_DISABLE(); __HAL_RCC_GPIOE_CLK_DISABLE(); __HAL_RCC_GPIOF_CLK_DISABLE(); __HAL_RCC_GPIOG_CLK_DISABLE(); } void mtqn_float_pins(){ GPIO_InitTypeDef GPIO_InitStruct; HAL_PWREx_EnablePullUpPullDownConfig(); /* Enable GPIOs clock */ __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); __HAL_RCC_GPIOH_CLK_ENABLE(); __HAL_RCC_GPIOE_CLK_ENABLE(); __HAL_RCC_GPIOF_CLK_ENABLE(); __HAL_RCC_GPIOG_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_All; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_All; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_All; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_All; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_All; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_All; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOF, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_All; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); /* Disable GPIOs clock */ __HAL_RCC_GPIOA_CLK_DISABLE(); __HAL_RCC_GPIOB_CLK_DISABLE(); __HAL_RCC_GPIOC_CLK_DISABLE(); __HAL_RCC_GPIOD_CLK_DISABLE(); __HAL_RCC_GPIOH_CLK_DISABLE(); __HAL_RCC_GPIOE_CLK_DISABLE(); __HAL_RCC_GPIOF_CLK_DISABLE(); __HAL_RCC_GPIOG_CLK_DISABLE(); } void mtqn_enter_stop_mode() { mtqn_save_gpio_state(); mtqn_float_pins(); SystemClock_Decrease(); /* Suspend Tick increment for power consumption purposes */ HAL_SuspendTick(); __HAL_RCC_TIM5_CLK_DISABLE(); // make sure wakeup flag is cleared __HAL_PWR_CLEAR_FLAG( PWR_FLAG_WUF1 | PWR_FLAG_WUF2 | PWR_FLAG_WUF3 | PWR_FLAG_WUF4 | PWR_FLAG_WUF5 | PWR_FLAG_WUFI); __HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB); HAL_PWREx_EnableInternalWakeUpLine(); HAL_PWREx_EnableLowPowerRunMode(); /* Enable Power Clock */ __HAL_RCC_PWR_CLK_ENABLE(); /* Ensure that MSI is wake-up system clock */ __HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_MSI); HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); HAL_PWREx_DisableLowPowerRunMode(); SetSysClock(); SystemCoreClockUpdate(); /* Resume Tick interrupt if disabled prior to Low Power Run mode entry */ HAL_ResumeTick(); __HAL_RCC_TIM5_CLK_ENABLE(); mtqn_restore_gpio_state(); } void mtqn_enter_standby_mode() { //mtqn_float_pins(); //mtqn_pull_down_pins(); /* Enable Power Clock */ __HAL_RCC_PWR_CLK_ENABLE(); /* Disable all used wakeup sources: WKUP pin */ HAL_PWR_DisableWakeUpPin(PWR_WAKEUP_PIN2); /* Clear wake up Flag */ __HAL_PWR_CLEAR_FLAG( PWR_FLAG_WUF1 | PWR_FLAG_WUF2 | PWR_FLAG_WUF3 | PWR_FLAG_WUF4 | PWR_FLAG_WUF5 | PWR_FLAG_WUFI); /* Enable wakeup pin WKUP2 */ HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN2_LOW); /* Set RTC back-up register RTC_BKP31R to indicate later on that system has entered shutdown mode */ WRITE_REG( RTC->BKP31R, 0x1 ); /* Enter shutdown mode */ HAL_PWREx_EnterSHUTDOWNMode(); } void mtqn_enable_standby_wake_pin() { HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1); } void mtqn_disable_standby_wake_pin() { HAL_PWR_DisableWakeUpPin(PWR_WAKEUP_PIN1); }