From 21b11a26ec7c08aba63530396ddf312033d621a3 Mon Sep 17 00:00:00 2001 From: svastm Date: Wed, 14 Sep 2016 15:35:51 +0200 Subject: [PATCH 1/2] STM32F4 - Add low power timer --- .../hal/TARGET_STM/TARGET_STM32F4/lp_ticker.c | 83 ++++++++++++++++ .../hal/TARGET_STM/TARGET_STM32F4/rtc_api.c | 95 +++++++++++++++++-- .../TARGET_STM/TARGET_STM32F4/rtc_api_hal.h | 79 +++++++++++++++ .../hal/TARGET_STM/TARGET_STM32F4/sleep.c | 6 ++ 4 files changed, 254 insertions(+), 9 deletions(-) create mode 100644 hal/targets/hal/TARGET_STM/TARGET_STM32F4/lp_ticker.c create mode 100644 hal/targets/hal/TARGET_STM/TARGET_STM32F4/rtc_api_hal.h diff --git a/hal/targets/hal/TARGET_STM/TARGET_STM32F4/lp_ticker.c b/hal/targets/hal/TARGET_STM/TARGET_STM32F4/lp_ticker.c new file mode 100644 index 0000000000..4415f74c9c --- /dev/null +++ b/hal/targets/hal/TARGET_STM/TARGET_STM32F4/lp_ticker.c @@ -0,0 +1,83 @@ +/* mbed Microcontroller Library + ******************************************************************************* + * Copyright (c) 2016, STMicroelectronics + * 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 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 "device.h" + +#if DEVICE_LOWPOWERTIMER + +#include "ticker_api.h" +#include "lp_ticker_api.h" +#include "rtc_api.h" +#include "rtc_api_hal.h" + +static uint8_t lp_ticker_inited = 0; + +void lp_ticker_init(void) +{ + if (lp_ticker_inited) return; + lp_ticker_inited = 1; + + rtc_init(); + rtc_set_irq_handler((uint32_t) lp_ticker_irq_handler); +} + +uint32_t lp_ticker_read(void) +{ + uint32_t usecs; + time_t time; + + lp_ticker_init(); + + do { + time = rtc_read(); + usecs = rtc_read_subseconds(); + } while (time != rtc_read()); + + return (time * 1000000) + usecs; +} + +void lp_ticker_set_interrupt(timestamp_t timestamp) +{ + uint32_t delta; + + delta = timestamp - lp_ticker_read(); + rtc_set_wake_up_timer(delta); +} + +void lp_ticker_disable_interrupt(void) +{ + rtc_deactivate_wake_up_timer(); +} + +void lp_ticker_clear_interrupt(void) +{ + +} + +#endif \ No newline at end of file diff --git a/hal/targets/hal/TARGET_STM/TARGET_STM32F4/rtc_api.c b/hal/targets/hal/TARGET_STM/TARGET_STM32F4/rtc_api.c index d583932a03..6770b78767 100644 --- a/hal/targets/hal/TARGET_STM/TARGET_STM32F4/rtc_api.c +++ b/hal/targets/hal/TARGET_STM/TARGET_STM32F4/rtc_api.c @@ -1,6 +1,6 @@ /* mbed Microcontroller Library ******************************************************************************* - * Copyright (c) 2014, STMicroelectronics + * Copyright (c) 2016, STMicroelectronics * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,6 +28,7 @@ ******************************************************************************* */ #include "rtc_api.h" +#include "rtc_api_hal.h" #if DEVICE_RTC @@ -39,12 +40,31 @@ static int rtc_inited = 0; static RTC_HandleTypeDef RtcHandle; +#if DEVICE_RTC_LSI + #define RTC_CLOCK LSI_VALUE +#else + #define RTC_CLOCK LSE_VALUE +#endif + +#if DEVICE_LOWPOWERTIMER + #define RTC_ASYNCH_PREDIV ((RTC_CLOCK - 1) / 0x8000) + #define RTC_SYNCH_PREDIV (RTC_CLOCK / (RTC_ASYNCH_PREDIV + 1) - 1) +#else + #define RTC_ASYNCH_PREDIV (0x007F) + #define RTC_SYNCH_PREDIV (RTC_CLOCK / (RTC_ASYNCH_PREDIV + 1) - 1) +#endif + +#if DEVICE_LOWPOWERTIMER + static void (*irq_handler)(void); + static void RTC_IRQHandler(); +#endif + void rtc_init(void) { RCC_OscInitTypeDef RCC_OscInitStruct; - uint32_t rtc_freq = 0; #if DEVICE_RTC_LSI + if (rtc_inited) return; rtc_inited = 1; #endif @@ -59,9 +79,7 @@ void rtc_init(void) // Connect LSE to RTC __HAL_RCC_RTC_CLKPRESCALER(RCC_RTCCLKSOURCE_LSE); __HAL_RCC_RTC_CONFIG(RCC_RTCCLKSOURCE_LSE); - rtc_freq = LSE_VALUE; - } - else { + } else { error("RTC error: LSE clock initialization failed."); } #else @@ -86,16 +104,14 @@ void rtc_init(void) // Connect LSI to RTC __HAL_RCC_RTC_CLKPRESCALER(RCC_RTCCLKSOURCE_LSI); __HAL_RCC_RTC_CONFIG(RCC_RTCCLKSOURCE_LSI); - // [TODO] This value is LSI typical value. To be measured precisely using a timer input capture - rtc_freq = LSI_VALUE; #endif // Enable RTC __HAL_RCC_RTC_ENABLE(); RtcHandle.Init.HourFormat = RTC_HOURFORMAT_24; - RtcHandle.Init.AsynchPrediv = 127; - RtcHandle.Init.SynchPrediv = (rtc_freq / 128) - 1; + RtcHandle.Init.AsynchPrediv = RTC_ASYNCH_PREDIV; + RtcHandle.Init.SynchPrediv = RTC_SYNCH_PREDIV; RtcHandle.Init.OutPut = RTC_OUTPUT_DISABLE; RtcHandle.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH; RtcHandle.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN; @@ -103,6 +119,20 @@ void rtc_init(void) if (HAL_RTC_Init(&RtcHandle) != HAL_OK) { error("RTC error: RTC initialization failed."); } + +#if DEVICE_LOWPOWERTIMER +#if DEVICE_RTC_LSI + rtc_write(0); +#else + if (!rtc_isenabled()) { + rtc_write(0); + } +#endif + NVIC_ClearPendingIRQ(RTC_WKUP_IRQn); + NVIC_DisableIRQ(RTC_WKUP_IRQn); + NVIC_SetVector(RTC_WKUP_IRQn, (uint32_t)RTC_IRQHandler); + NVIC_EnableIRQ(RTC_WKUP_IRQn); +#endif } void rtc_free(void) @@ -129,6 +159,7 @@ void rtc_free(void) RCC_OscInitStruct.LSIState = RCC_LSI_OFF; RCC_OscInitStruct.LSEState = RCC_LSE_OFF; HAL_RCC_OscConfig(&RCC_OscInitStruct); + #if DEVICE_RTC_LSI rtc_inited = 0; #endif @@ -218,4 +249,50 @@ void rtc_write(time_t t) HAL_RTC_SetTime(&RtcHandle, &timeStruct, FORMAT_BIN); } +#if DEVICE_LOWPOWERTIMER + +static void RTC_IRQHandler() +{ + HAL_RTCEx_WakeUpTimerIRQHandler(&RtcHandle); +} + +void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc) +{ + if (irq_handler) { + // Fire the user callback + irq_handler(); + } +} + +void rtc_set_irq_handler(uint32_t handler) +{ + irq_handler = (void (*)(void))handler; +} + +uint32_t rtc_read_subseconds(void) +{ + return 1000000.f * ((double)(RTC_SYNCH_PREDIV - RTC->SSR) / (RTC_SYNCH_PREDIV + 1)); +} + +void rtc_set_wake_up_timer(uint32_t delta) +{ + uint32_t wake_up_counter = delta / (2000000 / RTC_CLOCK); + + if (HAL_RTCEx_SetWakeUpTimer_IT(&RtcHandle, wake_up_counter, + RTC_WAKEUPCLOCK_RTCCLK_DIV2) != HAL_OK) { + error("Set wake up timer failed\n"); + } +} + +void rtc_deactivate_wake_up_timer(void) +{ + HAL_RTCEx_DeactivateWakeUpTimer(&RtcHandle); +} + +void rtc_synchronize(void) +{ + HAL_RTC_WaitForSynchro(&RtcHandle); +} +#endif // DEVICE_LOWPOWERTIMER + #endif diff --git a/hal/targets/hal/TARGET_STM/TARGET_STM32F4/rtc_api_hal.h b/hal/targets/hal/TARGET_STM/TARGET_STM32F4/rtc_api_hal.h new file mode 100644 index 0000000000..7954d40633 --- /dev/null +++ b/hal/targets/hal/TARGET_STM/TARGET_STM32F4/rtc_api_hal.h @@ -0,0 +1,79 @@ +/* mbed Microcontroller Library +******************************************************************************* +* Copyright (c) 2016, STMicroelectronics +* 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 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. +******************************************************************************* +*/ + +#ifndef MBED_RTC_API_HAL_H +#define MBED_RTC_API_HAL_H + +#include +#include "rtc_api.h" + +#ifdef __cplusplus +extern "C" { +#endif +/* + * Extend rtc_api.h + */ + +/** Set the given function as handler of wakeup timer event. + * + * @param handler The function to set as handler + */ +void rtc_set_irq_handler(uint32_t handler); + +/** Read the subsecond register. + * + * @return The remaining time as microseconds (0-999999) + */ +uint32_t rtc_read_subseconds(void); + +/** Program a wake up timer event in delta microseconds. + * + * @param delta The time to wait + */ +void rtc_set_wake_up_timer(uint32_t delta); + +/** Disable the wake up timer event. + * + * The wake up timer use auto reload, you have to deactivate it manually. + */ +void rtc_deactivate_wake_up_timer(void); + +/** Synchronise the RTC shadow registers. + * + * Must be called after a deepsleep. + */ +void rtc_synchronize(void); + + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/hal/targets/hal/TARGET_STM/TARGET_STM32F4/sleep.c b/hal/targets/hal/TARGET_STM/TARGET_STM32F4/sleep.c index 943d4c717a..d14fc098fb 100644 --- a/hal/targets/hal/TARGET_STM/TARGET_STM32F4/sleep.c +++ b/hal/targets/hal/TARGET_STM/TARGET_STM32F4/sleep.c @@ -28,6 +28,8 @@ ******************************************************************************* */ #include "sleep_api.h" +#include "rtc_api_hal.h" + #if DEVICE_SLEEP #include "cmsis.h" @@ -49,6 +51,10 @@ void deepsleep(void) // After wake-up from STOP reconfigure the PLL SetSysClock(); + +#if DEVICE_LOWPOWERTIMER + rtc_synchronize(); +#endif } #endif From 0766d397463c569f73fce5d2ae3e2c00bc00ee31 Mon Sep 17 00:00:00 2001 From: svastm Date: Wed, 14 Sep 2016 15:36:04 +0200 Subject: [PATCH 2/2] STM32F4 - Enable the low power timer Enable the low power timer for the following targets: - NUCLEO_F411RE - NUCLEO_F401RE - DISCO_F429ZI - NUCLEO_F446RE - NUCLEO_F410RB - DISCO_F469NI - NUCLEO_F446ZE - B86B_F446VE --- hal/targets.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hal/targets.json b/hal/targets.json index 98e827044a..dffaa479ba 100644 --- a/hal/targets.json +++ b/hal/targets.json @@ -795,7 +795,7 @@ "progen": {"target": "nucleo-f410rb"}, "macros": ["TRANSACTION_QUEUE_SIZE_SPI=2"], "detect_code": ["0740"], - "device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "TRNG"], + "device_has": ["ANALOGIN", "ANALOGOUT", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "TRNG"], "release_versions": ["2", "5"] }, "NUCLEO_F411RE": { @@ -808,7 +808,7 @@ "progen": {"target": "nucleo-f411re"}, "detect_code": ["0740"], "macros": ["TRANSACTION_QUEUE_SIZE_SPI=2"], - "device_has": ["ANALOGIN", "ERROR_RED", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"], + "device_has": ["ANALOGIN", "ERROR_RED", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"], "release_versions": ["2", "5"] }, "ELMO_F411RE": { @@ -833,7 +833,7 @@ "supported_toolchains": ["ARM", "uARM", "GCC_ARM", "IAR"], "progen": {"target": "nucleo-f429zi"}, "macros": ["DEVICE_RTC_LSI=1", "TRANSACTION_QUEUE_SIZE_SPI=2"], - "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "ERROR_RED", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "RTC_LSI", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "TRNG"], + "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "ERROR_RED", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "RTC_LSI", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "TRNG"], "detect_code": ["0796"], "features": ["IPV4"], "release_versions": ["2", "5"] @@ -848,7 +848,7 @@ "progen": {"target": "nucleo-f446re"}, "detect_code": ["0777"], "macros": ["TRANSACTION_QUEUE_SIZE_SPI=2"], - "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "ERROR_RED", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"], + "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "ERROR_RED", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"], "release_versions": ["2", "5"] }, "NUCLEO_F446ZE": { @@ -861,7 +861,7 @@ "progen": {"target": "nucleo-f446ze"}, "detect_code": ["0778"], "macros": ["TRANSACTION_QUEUE_SIZE_SPI=2"], - "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "ERROR_RED", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"], + "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "ERROR_RED", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"], "release_versions": ["2", "5"] }, @@ -874,7 +874,7 @@ "inherits": ["Target"], "detect_code": ["0840"], "macros": ["TRANSACTION_QUEUE_SIZE_SPI=2"], - "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"], + "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES"], "release_versions": ["2", "5"] }, "NUCLEO_F746ZG": { @@ -1088,7 +1088,7 @@ "macros": ["TRANSACTION_QUEUE_SIZE_SPI=2"], "progen": {"target": "disco-f469ni"}, "detect_code": ["0788"], - "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES", "TRNG"], + "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "ERROR_RED", "I2C", "I2CSLAVE", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES", "TRNG"], "release_versions": ["2", "5"] }, "DISCO_L053C8": {