diff --git a/cores/arduino/HardwareSerial.cpp b/cores/arduino/HardwareSerial.cpp index 9f24275905..f8554a588e 100644 --- a/cores/arduino/HardwareSerial.cpp +++ b/cores/arduino/HardwareSerial.cpp @@ -380,5 +380,6 @@ void HardwareSerial::setRx(PinName _rx) { void HardwareSerial::setTx(PinName _tx){ _serial.pin_tx = _tx; } + #endif // HAVE_HWSERIALx #endif // !NO_HWSERIAL diff --git a/cores/arduino/HardwareSerial.h b/cores/arduino/HardwareSerial.h index 81a48add5f..65743eb2bb 100644 --- a/cores/arduino/HardwareSerial.h +++ b/cores/arduino/HardwareSerial.h @@ -125,6 +125,8 @@ class HardwareSerial : public Stream void setRx(PinName _rx); void setTx(PinName _tx); + friend class STM32LowPower; + // Interrupt handlers static void _rx_complete_irq(serial_t* obj); static int _tx_complete_irq(serial_t* obj); diff --git a/cores/arduino/board.h b/cores/arduino/board.h index 194f4ebd7a..5d075f372f 100644 --- a/cores/arduino/board.h +++ b/cores/arduino/board.h @@ -14,6 +14,7 @@ extern "C"{ #include "digital_io.h" #include "hal_uart_emul.h" #include "hw_config.h" +#include "LowPower.h" #include "spi_com.h" #include "stm32_eeprom.h" #include "timer.h" diff --git a/cores/arduino/stm32/LowPower.c b/cores/arduino/stm32/LowPower.c new file mode 100644 index 0000000000..8f2f5a654b --- /dev/null +++ b/cores/arduino/stm32/LowPower.c @@ -0,0 +1,335 @@ +/** + ****************************************************************************** + * @file LowPower.c + * @author WI6LABS + * @version V1.0.0 + * @date 17 - November -2017 + * @brief Provides a Low Power interface + * + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * 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 STMicroelectronics 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 "Arduino.h" +#include "LowPower.h" + +#ifdef HAL_PWR_MODULE_ENABLED + +#ifdef __cplusplus + extern "C" { +#endif + +// NOTE: is these pins are common to a MCU family? +/* Wakeup pins list. Allow to know which pins can be used as wake up pin in +standby or shutdown mode */ +#if defined(STM32L053xx) +const PinMap PinMap_WKUP[] = { + {PA_0, NP, 1}, //WKUP1 + {PC_13, NP, 2}, //WKUP2 + {NC, NP, 0} +}; +#elif defined(STM32L476xx) +const PinMap PinMap_WKUP[] = { + {PA_0, NP, 1}, //WKUP1 + {PC_13, NP, 2}, //WKUP2 + {PE_6, NP, 3}, //WKUP3 + {PA_2, NP, 4}, //WKUP4 + {PC_5, NP, 5}, //WKUP5 + {NC, NP, 0} +}; +#else +const PinMap PinMap_WKUP[] = { + {NC, NP, 0} +}; +#endif + +// Save UART handler for callback +static UART_HandleTypeDef* WakeUpUart = NULL; +// Save callback pointer +static void (*WakeUpUartCb)( void ) = NULL; + +/** + * @brief Initialize low power mode + * @param None + * @retval None + */ +void LowPower_init(){ + /* Enable Power Clock */ + __HAL_RCC_PWR_CLK_ENABLE(); + + /* Ensure that HSI is wake-up system clock */ +#if defined(STM32L0xx) || defined(STM32L4xx) + __HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_HSI); +#endif // STM32L0xx || STM32L4xx + + /* Check if the system was resumed from StandBy mode */ + if (__HAL_PWR_GET_FLAG(PWR_FLAG_SB) != RESET) + { + /* Clear Standby flag */ + __HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB); + } + + /* Clear all related wakeup flags */ + __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU); +} + +/** + * @brief Configure a pin as wakeup source if compatible. + * @param pin: pin to configure + * @param mode: pin mode (edge or state). The configuration have to be compatible. + * @retval None + */ +void LowPower_EnableWakeUpPin(uint32_t pin, uint32_t mode) { +#ifndef STM32L4xx + UNUSED(mode); +#endif + PinName p = digitalPinToPinName(pin); + uint32_t wupPin = pinmap_find_function(p, PinMap_WKUP); + switch (wupPin) { +#ifdef PWR_WAKEUP_PIN1 + case 1 : + #ifdef STM32L4xx + if (mode == RISING) { + HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1_HIGH); + } + else { + HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1_LOW); + } + #else + HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1); + #endif + break; +#endif //PWR_WAKEUP_PIN1 +#ifdef PWR_WAKEUP_PIN2 + case 2 : + #ifdef STM32L4xx + if (mode == RISING) { + HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN2_HIGH); + } + else { + HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN2_LOW); + } + #else + HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN2); + #endif + break; +#endif //PWR_WAKEUP_PIN2 +#ifdef PWR_WAKEUP_PIN3 + case 3 : + #ifdef STM32L4xx + if (mode == RISING) { + HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN3_HIGH); + } + else { + HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN3_LOW); + } + #else + HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN3); + #endif + break; +#endif //PWR_WAKEUP_PIN3 +#ifdef PWR_WAKEUP_PIN4 + case 4 : + #ifdef STM32L4xx + if (mode == RISING) { + HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN4_HIGH); + } + else { + HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN4_LOW); + } + #else + HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN4); + #endif + break; +#endif //PWR_WAKEUP_PIN4 +#ifdef PWR_WAKEUP_PIN5 + case 5 : + #ifdef STM32L4xx + if (mode == RISING) { + HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN5_HIGH); + } + else { + HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN5_LOW); + } + #else + HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN5); + #endif + break; +#endif //PWR_WAKEUP_PIN5 + default : + break; + } +} + +/** + * @brief Enable the sleep mode. + * @param None + * @retval None + */ +void LowPower_sleep(uint32_t regulator){ + __disable_irq(); + /*Suspend Tick increment to prevent wakeup by Systick interrupt. + Otherwise the Systick interrupt will wake up the device within 1ms (HAL time base)*/ + HAL_SuspendTick(); + + /* Enter Sleep Mode , wake up is done once User push-button is pressed */ + HAL_PWR_EnterSLEEPMode(regulator, PWR_SLEEPENTRY_WFI); + + /* Resume Tick interrupt if disabled prior to SLEEP mode entry */ + HAL_ResumeTick(); + __enable_irq(); + + if (WakeUpUartCb != NULL) { + WakeUpUartCb(); + } +} + +/** + * @brief Enable the stop mode. + * @param None + * @retval None + */ +void LowPower_stop(){ + __disable_irq(); + +#if STM32L4xx + if (WakeUpUart != NULL) { + HAL_UARTEx_EnableStopMode(WakeUpUart); + } +#endif + +#ifdef STM32L0xx + /* Enable Ultra low power mode */ + HAL_PWREx_EnableUltraLowPower(); + + /* Enable the fast wake up from Ultra low power mode */ + HAL_PWREx_EnableFastWakeUp(); + + /* Select HSI as system clock source after Wake Up from Stop mode */ + __HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_HSI); +#endif + + // Enter Stop mode + HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); + + // Exit Stop mode reset clocks + SystemClock_Config(); + __enable_irq(); + +#if STM32L4xx + if (WakeUpUart != NULL) { + HAL_UARTEx_DisableStopMode(WakeUpUart); + + if (WakeUpUartCb != NULL) { + WakeUpUartCb(); + } + } +#endif +} + +/** + * @brief Enable the standby mode. The board reset when leaves this mode. + * @param None + * @retval None + */ +void LowPower_standby(){ + __disable_irq(); + +#ifdef STM32L0xx + /* Enable Ultra low power mode */ + HAL_PWREx_EnableUltraLowPower(); + + /* Enable the fast wake up from Ultra low power mode */ + HAL_PWREx_EnableFastWakeUp(); +#endif + + HAL_PWR_EnterSTANDBYMode(); +} + +/** + * @brief Enable the shutdown mode.The board reset when leaves this mode. + * If shutdown mode not available, use standby mode instead. + * @param None + * @retval None + */ +void LowPower_shutdown(){ + __disable_irq(); +#ifdef STM32L4xx + // LSE must be on to use shutdown mode + if(__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == SET) { + HAL_PWREx_EnterSHUTDOWNMode(); + } else { + LowPower_standby(); + } +#else + LowPower_standby(); +#endif +} + +/** + * @brief Configure the UART as a wakeup source. A callback can be called when + * the chip leaves the low power mode. See board datasheet to check + * with which low power mode the UART is compatible. + * @param serial: pointer to serial + * @param FuncPtr: pointer to callback + * @retval None + */ +void LowPower_EnableWakeUpUart(serial_t* serial, void (*FuncPtr)( void ) ) { +#if defined(STM32L0xx) || defined(STM32L4xx) + UART_WakeUpTypeDef WakeUpSelection; + + // Save Uart handler + WakeUpUart = &(serial->handle); + + // Save callback + WakeUpUartCb = FuncPtr; + + /* make sure that no UART transfer is on-going */ + while(__HAL_UART_GET_FLAG(WakeUpUart, USART_ISR_BUSY) == SET); + /* make sure that UART is ready to receive + * (test carried out again later in HAL_UARTEx_StopModeWakeUpSourceConfig) */ + while(__HAL_UART_GET_FLAG(WakeUpUart, USART_ISR_REACK) == RESET); + + /* set the wake-up event: + * specify wake-up on RXNE flag */ + WakeUpSelection.WakeUpEvent = UART_WAKEUP_ON_READDATA_NONEMPTY; + HAL_UARTEx_StopModeWakeUpSourceConfig(WakeUpUart, WakeUpSelection); + + /* Enable the UART Wake UP from STOP1 mode Interrupt */ + __HAL_UART_ENABLE_IT(WakeUpUart, UART_IT_WUF); +#endif // STM32L0xx || STM32L4xx +} + +#ifdef __cplusplus +} +#endif + +#endif // HAL_PWR_MODULE_ENABLED + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/cores/arduino/stm32/LowPower.h b/cores/arduino/stm32/LowPower.h new file mode 100644 index 0000000000..b6c901b9f2 --- /dev/null +++ b/cores/arduino/stm32/LowPower.h @@ -0,0 +1,71 @@ +/** + ****************************************************************************** + * @file LowPower.h + * @author WI6LABS + * @version V1.0.0 + * @date 17 - November -2017 + * @brief Header for Low Power module + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __LOW_POWER_H +#define __LOW_POWER_H + +/* Includes ------------------------------------------------------------------*/ +#include "stm32_def.h" +#include "uart.h" + +#ifdef HAL_PWR_MODULE_ENABLED + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ + +void LowPower_init(); +void LowPower_EnableWakeUpPin(uint32_t pin, uint32_t mode); +void LowPower_EnableWakeUpUart(serial_t* serial, void (*FuncPtr)( void ) ); +void LowPower_sleep(uint32_t regulator); +void LowPower_stop(); +void LowPower_standby(); +void LowPower_shutdown(); + +#ifdef __cplusplus + } +#endif + +#endif // HAL_PWR_MODULE_ENABLED + +#endif /* __LOW_POWER_H */ diff --git a/cores/arduino/stm32/uart.c b/cores/arduino/stm32/uart.c index af72dd5fa1..070326a6dd 100644 --- a/cores/arduino/stm32/uart.c +++ b/cores/arduino/stm32/uart.c @@ -125,9 +125,14 @@ void uart_init(serial_t *obj) printf("ERROR: UART pins mismatch\n"); return; } + // Enable USART clock #if defined(USART1_BASE) else if(obj->uart == USART1) { +#ifdef STM32L4xx + // Configure HSI as source clock for low power wakeup clock + __HAL_RCC_USART1_CONFIG(RCC_USART1CLKSOURCE_HSI); +#endif __HAL_RCC_USART1_FORCE_RESET(); __HAL_RCC_USART1_RELEASE_RESET(); __HAL_RCC_USART1_CLK_ENABLE(); @@ -137,6 +142,10 @@ void uart_init(serial_t *obj) #endif #if defined(USART2_BASE) else if(obj->uart == USART2) { +#ifdef STM32L4xx + // Configure HSI as source clock for low power wakeup clock + __HAL_RCC_USART2_CONFIG(RCC_USART2CLKSOURCE_HSI); +#endif __HAL_RCC_USART2_FORCE_RESET(); __HAL_RCC_USART2_RELEASE_RESET(); __HAL_RCC_USART2_CLK_ENABLE(); @@ -146,6 +155,10 @@ void uart_init(serial_t *obj) #endif #if defined(USART3_BASE) else if(obj->uart == USART3) { +#ifdef STM32L4xx + // Configure HSI as source clock for low power wakeup clock + __HAL_RCC_USART3_CONFIG(RCC_USART3CLKSOURCE_HSI); +#endif __HAL_RCC_USART3_FORCE_RESET(); __HAL_RCC_USART3_RELEASE_RESET(); __HAL_RCC_USART3_CLK_ENABLE(); @@ -155,6 +168,10 @@ void uart_init(serial_t *obj) #endif #if defined(UART4_BASE) else if(obj->uart == UART4) { +#ifdef STM32L4xx + // Configure HSI as source clock for low power wakeup clock + __HAL_RCC_UART4_CONFIG(RCC_UART4CLKSOURCE_HSI); +#endif __HAL_RCC_UART4_FORCE_RESET(); __HAL_RCC_UART4_RELEASE_RESET(); __HAL_RCC_UART4_CLK_ENABLE(); @@ -172,6 +189,10 @@ void uart_init(serial_t *obj) #endif #if defined(UART5_BASE) else if(obj->uart == UART5) { +#ifdef STM32L4xx + // Configure HSI as source clock for low power wakeup clock + __HAL_RCC_UART5_CONFIG(RCC_UART5CLKSOURCE_HSI); +#endif __HAL_RCC_UART5_FORCE_RESET(); __HAL_RCC_UART5_RELEASE_RESET(); __HAL_RCC_UART5_CLK_ENABLE(); @@ -288,6 +309,9 @@ void uart_init(serial_t *obj) huart->Init.Mode = UART_MODE_TX_RX; huart->Init.HwFlowCtl = UART_HWCONTROL_NONE; huart->Init.OverSampling = UART_OVERSAMPLING_16; +#if defined(STM32F0xx) || defined(STM32F3xx) || defined(STM32F7xx) || defined(STM32L0xx) || defined(STM32L4xx) + huart->AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; +#endif // STM32F0xx || STM32F3xx || STM32F7xx || STM32L0xx || STM32L4xx // huart->Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; if(HAL_UART_Init(huart) != HAL_OK) { @@ -866,6 +890,19 @@ void UART10_IRQHandler(void) } #endif +/** + * @brief HAL UART Call Back + * @param UART handler + * @retval None + */ +void HAL_UARTEx_WakeupCallback(UART_HandleTypeDef *huart) +{ + uint8_t index = uart_index(huart); + serial_t *obj = rx_callback_obj[index]; + + HAL_UART_Receive_IT(huart, &(obj->recv), 1); +} + #ifdef __cplusplus } #endif diff --git a/variants/NUCLEO_L476RG/variant.cpp b/variants/NUCLEO_L476RG/variant.cpp index fbc037671d..641f8f3ab1 100644 --- a/variants/NUCLEO_L476RG/variant.cpp +++ b/variants/NUCLEO_L476RG/variant.cpp @@ -103,19 +103,19 @@ extern "C" { /** * @brief System Clock Configuration * The system Clock is configured as follows : - * System Clock source = PLL (MSI) + * System Clock source = PLL (HSI) * SYSCLK(Hz) = 80000000 * HCLK(Hz) = 80000000 * AHB Prescaler = 1 * APB1 Prescaler = 1 * APB2 Prescaler = 1 - * MSI Frequency(Hz) = 4000000 + * HSI Frequency(Hz) = 16000000 * PLL_M = 1 - * PLL_N = 40 + * PLL_N = 10 * PLL_R = 2 * PLL_P = 7 - * PLL_Q = 4 - * Flash Latency(WS) = 4 + * PLL_Q = 2 + * Flash Latency(WS) = 3 * @param None * @retval None */ @@ -124,20 +124,16 @@ WEAK void SystemClock_Config(void) RCC_OscInitTypeDef RCC_OscInitStruct = {}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {}; - /* MSI is enabled after System reset, activate PLL with MSI as source */ - RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI; - RCC_OscInitStruct.MSIState = RCC_MSI_ON; - - RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6; - RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT; + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; + RCC_OscInitStruct.HSIState = RCC_HSI_ON; + RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; - RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; RCC_OscInitStruct.PLL.PLLM = 1; - RCC_OscInitStruct.PLL.PLLN = 40; + RCC_OscInitStruct.PLL.PLLN = 10; RCC_OscInitStruct.PLL.PLLR = 2; RCC_OscInitStruct.PLL.PLLP = 7; - RCC_OscInitStruct.PLL.PLLQ = 4; - + RCC_OscInitStruct.PLL.PLLQ = 2; if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { /* Initialization Error */ @@ -151,7 +147,7 @@ WEAK void SystemClock_Config(void) RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; - if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) + if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK) { /* Initialization Error */ while(1);