From 35d101ee50b0b9fa5c75de40903aee0c44ce4f44 Mon Sep 17 00:00:00 2001 From: svastm Date: Fri, 16 Sep 2016 10:34:34 +0200 Subject: [PATCH 1/2] STM32L4 - Add low power timer --- .../hal/TARGET_STM/TARGET_STM32L4/lp_ticker.c | 83 +++++++++++++++++ .../hal/TARGET_STM/TARGET_STM32L4/rtc_api.c | 88 +++++++++++++++++-- .../TARGET_STM/TARGET_STM32L4/rtc_api_hal.h | 79 +++++++++++++++++ .../hal/TARGET_STM/TARGET_STM32L4/sleep.c | 5 ++ 4 files changed, 249 insertions(+), 6 deletions(-) create mode 100644 hal/targets/hal/TARGET_STM/TARGET_STM32L4/lp_ticker.c create mode 100644 hal/targets/hal/TARGET_STM/TARGET_STM32L4/rtc_api_hal.h diff --git a/hal/targets/hal/TARGET_STM/TARGET_STM32L4/lp_ticker.c b/hal/targets/hal/TARGET_STM/TARGET_STM32L4/lp_ticker.c new file mode 100644 index 00000000000..4415f74c9c9 --- /dev/null +++ b/hal/targets/hal/TARGET_STM/TARGET_STM32L4/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_STM32L4/rtc_api.c b/hal/targets/hal/TARGET_STM/TARGET_STM32L4/rtc_api.c index 0dd3d45d4de..2581c236cda 100644 --- a/hal/targets/hal/TARGET_STM/TARGET_STM32L4/rtc_api.c +++ b/hal/targets/hal/TARGET_STM/TARGET_STM32L4/rtc_api.c @@ -28,6 +28,7 @@ ******************************************************************************* */ #include "rtc_api.h" +#include "rtc_api_hal.h" #if DEVICE_RTC @@ -39,11 +40,29 @@ 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(void); +#endif + void rtc_init(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; - uint32_t rtc_freq = 0; #if DEVICE_RTC_LSI if (rtc_inited) return; @@ -63,7 +82,6 @@ void rtc_init(void) PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC; PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE; HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct); - rtc_freq = LSE_VALUE; } else { error("Cannot initialize RTC with LSE\n"); } @@ -92,8 +110,6 @@ void rtc_init(void) if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { error("Cannot initialize RTC with LSI\n"); } - // This value is LSI typical value (see device datasheet) - rtc_freq = 32000; #endif // Check if RTC is already initialized @@ -103,8 +119,8 @@ void rtc_init(void) __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; @@ -112,6 +128,20 @@ void rtc_init(void) if (HAL_RTC_Init(&RtcHandle) != HAL_OK) { error("Cannot initialize RTC\n"); } + +#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) @@ -231,4 +261,50 @@ void rtc_write(time_t t) HAL_RTC_SetTime(&RtcHandle, &timeStruct, RTC_FORMAT_BIN); } +#if DEVICE_LOWPOWERTIMER + +static void RTC_IRQHandler(void) +{ + 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_STM32L4/rtc_api_hal.h b/hal/targets/hal/TARGET_STM/TARGET_STM32L4/rtc_api_hal.h new file mode 100644 index 00000000000..14a345438d3 --- /dev/null +++ b/hal/targets/hal/TARGET_STM/TARGET_STM32L4/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 diff --git a/hal/targets/hal/TARGET_STM/TARGET_STM32L4/sleep.c b/hal/targets/hal/TARGET_STM/TARGET_STM32L4/sleep.c index 6fb162e453a..46486b07051 100644 --- a/hal/targets/hal/TARGET_STM/TARGET_STM32L4/sleep.c +++ b/hal/targets/hal/TARGET_STM/TARGET_STM32L4/sleep.c @@ -28,6 +28,7 @@ ******************************************************************************* */ #include "sleep_api.h" +#include "rtc_api_hal.h" #if DEVICE_SLEEP @@ -55,6 +56,10 @@ void deepsleep(void) // Restart HAL systick HAL_ResumeTick(); + +#if DEVICE_LOWPOWERTIMER + rtc_synchronize(); +#endif } #endif From 883ff3a1d4d4ad259b24fae210f78905d859e4cf Mon Sep 17 00:00:00 2001 From: svastm Date: Fri, 16 Sep 2016 10:35:16 +0200 Subject: [PATCH 2/2] STM32L4 - Enable the low power timer Enable the low power timer for the following targets: - DISCO_L476VG - NUCLEO_L432KC - NUCLEO_L476RG --- hal/targets.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hal/targets.json b/hal/targets.json index b948d3de9df..6ef5efa7de5 100644 --- a/hal/targets.json +++ b/hal/targets.json @@ -977,7 +977,7 @@ "inherits": ["Target"], "progen": {"target": "nucleo-l432kc"}, "detect_code": ["0770"], - "device_has": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "CAN", "STDIO_MESSAGES"], + "device_has": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "CAN", "STDIO_MESSAGES"], "release_versions": ["2", "5"] }, "NUCLEO_L476RG": { @@ -989,7 +989,7 @@ "inherits": ["Target"], "progen": {"target": "nucleo-l476rg"}, "detect_code": ["0765"], - "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"], + "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "I2C", "I2CSLAVE", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"], "release_versions": ["2", "5"] }, "STM32F3XX": { @@ -1131,7 +1131,7 @@ "supported_toolchains": ["ARM", "uARM", "IAR", "GCC_ARM"], "progen": {"target": "disco-l476vg"}, "detect_code": ["0820"], - "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"], + "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "I2C", "I2CSLAVE", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES"], "release_versions": ["2", "5"] }, "MTS_MDOT_F405RG": {