STM32 LPTICKER update for targets supporting RTC

pull/7009/head
jeromecoutant 2018-04-24 14:06:57 +02:00 committed by Bartek Szatkowski
parent 39a9801675
commit e3deaecc27
3 changed files with 103 additions and 80 deletions

View File

@ -173,8 +173,8 @@ static void LPTIM1_IRQHandler(void)
/* Clear Compare match flag */
__HAL_LPTIM_CLEAR_FLAG(&LptimHandle, LPTIM_FLAG_CMPM);
if (irq_handler) {
irq_handler();
if (irq_handler) {
irq_handler();
}
}
}
@ -240,28 +240,35 @@ void lp_ticker_clear_interrupt(void)
#else /* MBED_CONF_TARGET_LPTICKER_LPTIM */
#include "rtc_api_hal.h"
const ticker_info_t* lp_ticker_get_info()
{
static const ticker_info_t info = {
RTC_CLOCK/4, // RTC_WAKEUPCLOCK_RTCCLK_DIV4
32
};
return &info;
}
void lp_ticker_init(void)
{
rtc_init();
lp_ticker_disable_interrupt();
}
uint32_t lp_ticker_read(void)
{
uint32_t usecs = rtc_read_us();
return usecs;
return rtc_read_lp();
}
void lp_ticker_set_interrupt(timestamp_t timestamp)
{
uint32_t delta;
delta = timestamp - lp_ticker_read();
rtc_set_wake_up_timer(delta);
rtc_set_wake_up_timer(timestamp);
}
void lp_ticker_fire_interrupt(void)
{
NVIC_SetPendingIRQ(RTC_WKUP_IRQn);
rtc_fire_interrupt();
}
void lp_ticker_disable_interrupt(void)
@ -271,7 +278,7 @@ void lp_ticker_disable_interrupt(void)
void lp_ticker_clear_interrupt(void)
{
NVIC_ClearPendingIRQ(RTC_WKUP_IRQn);
NVIC_DisableIRQ(RTC_WKUP_IRQn);
}
#endif /* MBED_CONF_TARGET_LPTICKER_LPTIM */

View File

@ -36,15 +36,6 @@
static RTC_HandleTypeDef RtcHandle;
#if DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM
#define GET_TICK_PERIOD(VALUE) (2048 * 1000000 / VALUE) /* 1s / SynchPrediv value * 2^11 (value to get the maximum precision value with no u32 overflow) */
static void (*irq_handler)(void);
static void RTC_IRQHandler(void);
static uint32_t lp_TickPeriod_us = GET_TICK_PERIOD(4095); /* default SynchPrediv value = 4095 */
#endif /* DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM */
void rtc_init(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
@ -119,10 +110,6 @@ void rtc_init(void)
RtcHandle.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
#endif /* TARGET_STM32F1 */
#if DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM
lp_TickPeriod_us = GET_TICK_PERIOD(RtcHandle.Init.SynchPrediv);
#endif
if (HAL_RTC_Init(&RtcHandle) != HAL_OK) {
error("RTC initialization failed");
}
@ -288,18 +275,41 @@ void rtc_synchronize(void)
#if DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM
static void RTC_IRQHandler(void);
static void (*irq_handler)(void);
volatile uint8_t lp_Fired = 0;
volatile uint32_t LP_continuous_time = 0;
volatile uint32_t LP_last_RTC_time = 0;
static void RTC_IRQHandler(void)
{
/* Update HAL state */
RtcHandle.Instance = RTC;
HAL_RTCEx_WakeUpTimerIRQHandler(&RtcHandle);
/* In case of registered handler, call it. */
if (irq_handler) {
irq_handler();
if(__HAL_RTC_WAKEUPTIMER_GET_IT(&RtcHandle, RTC_IT_WUT)) {
/* Get the status of the Interrupt */
if((uint32_t)(RTC->CR & RTC_IT_WUT) != (uint32_t)RESET) {
/* Clear the WAKEUPTIMER interrupt pending bit */
__HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(&RtcHandle, RTC_FLAG_WUTF);
lp_Fired = 0;
if (irq_handler) {
irq_handler();
}
}
}
if (lp_Fired) {
lp_Fired = 0;
if (irq_handler) {
irq_handler();
}
}
__HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_FLAG();
}
uint32_t rtc_read_us(void)
uint32_t rtc_read_lp(void)
{
RTC_TimeTypeDef timeStruct = {0};
RTC_DateTypeDef dateStruct = {0};
@ -316,52 +326,52 @@ uint32_t rtc_read_us(void)
time/date is one second less than as indicated by RTC_TR/RTC_DR. */
timeStruct.Seconds -= 1;
}
uint32_t RTCTime = timeStruct.Seconds + timeStruct.Minutes * 60 + timeStruct.Hours * 60 * 60;
uint32_t Time_us = ((timeStruct.SecondFraction - timeStruct.SubSeconds) * lp_TickPeriod_us) >> 11;
uint32_t RTC_time_s = timeStruct.Seconds + timeStruct.Minutes * 60 + timeStruct.Hours * 60 * 60; // Max 0x0001-517F => * 8191 + 8191 = 0x2A2E-AE80
return (RTCTime * 1000000) + Time_us ;
if (LP_last_RTC_time <= RTC_time_s) {
LP_continuous_time += (RTC_time_s - LP_last_RTC_time);
} else {
LP_continuous_time += (24 * 60 * 60 + RTC_time_s - LP_last_RTC_time);
}
LP_last_RTC_time = RTC_time_s;
return LP_continuous_time * PREDIV_S_VALUE + timeStruct.SecondFraction - timeStruct.SubSeconds;
}
void rtc_set_wake_up_timer(uint32_t delta)
void rtc_set_wake_up_timer(timestamp_t timestamp)
{
#define RTC_CLOCK_US (((uint64_t)RTC_CLOCK << 32 ) / 1000000)
uint32_t WakeUpCounter;
uint32_t WakeUpClock;
uint32_t current_lp_time;
/* Ex for Wakeup period resolution with RTCCLK=32768 Hz :
* RTCCLK_DIV2: ~122us < wakeup period < ~4s
* RTCCLK_DIV4: ~244us < wakeup period < ~8s
* RTCCLK_DIV8: ~488us < wakeup period < ~16s
* RTCCLK_DIV16: ~976us < wakeup period < ~32s
* CK_SPRE_16BITS: 1s < wakeup period < (0xFFFF+ 1) x 1 s = 65536 s (18 hours)
* CK_SPRE_17BITS: 18h+1s < wakeup period < (0x1FFFF+ 1) x 1 s = 131072 s (36 hours)
*/
if (delta < (0x10000 * 2 / RTC_CLOCK * 1000000) ) { // (0xFFFF + 1) * RTCCLK_DIV2 / RTC_CLOCK * 1s
WakeUpCounter = (((uint64_t)delta * RTC_CLOCK_US) >> 32) >> 1 ;
WakeUpClock = RTC_WAKEUPCLOCK_RTCCLK_DIV2;
} else if (delta < (0x10000 * 4 / RTC_CLOCK * 1000000) ) {
WakeUpCounter = (((uint64_t)delta * RTC_CLOCK_US) >> 32) >> 2 ;
WakeUpClock = RTC_WAKEUPCLOCK_RTCCLK_DIV4;
} else if (delta < (0x10000 * 8 / RTC_CLOCK * 1000000) ) {
WakeUpCounter = (((uint64_t)delta * RTC_CLOCK_US) >> 32) >> 3 ;
WakeUpClock = RTC_WAKEUPCLOCK_RTCCLK_DIV8;
} else if (delta < (0x10000 * 16 / RTC_CLOCK * 1000000) ) {
WakeUpCounter = (((uint64_t)delta * RTC_CLOCK_US) >> 32) >> 4 ;
WakeUpClock = RTC_WAKEUPCLOCK_RTCCLK_DIV16;
current_lp_time = rtc_read_lp();
if (timestamp < current_lp_time) {
WakeUpCounter = 0xFFFFFFFF - current_lp_time + timestamp;
} else {
WakeUpCounter = (delta / 1000000) ;
WakeUpClock = RTC_WAKEUPCLOCK_CK_SPRE_16BITS;
WakeUpCounter = timestamp - current_lp_time;
}
irq_handler = (void (*)(void))lp_ticker_irq_handler;
NVIC_SetVector(RTC_WKUP_IRQn, (uint32_t)RTC_IRQHandler);
NVIC_EnableIRQ(RTC_WKUP_IRQn);
if (WakeUpCounter > 0xFFFF) {
WakeUpCounter = 0xFFFF;
}
RtcHandle.Instance = RTC;
if (HAL_RTCEx_SetWakeUpTimer_IT(&RtcHandle, (uint32_t)WakeUpCounter, WakeUpClock) != HAL_OK) {
if (HAL_RTCEx_SetWakeUpTimer_IT(&RtcHandle, WakeUpCounter, RTC_WAKEUPCLOCK_RTCCLK_DIV4) != HAL_OK) {
error("rtc_set_wake_up_timer init error\n");
}
NVIC_SetVector(RTC_WKUP_IRQn, (uint32_t)RTC_IRQHandler);
irq_handler = (void (*)(void))lp_ticker_irq_handler;
NVIC_EnableIRQ(RTC_WKUP_IRQn);
}
void rtc_fire_interrupt(void)
{
lp_Fired = 1;
NVIC_SetVector(RTC_WKUP_IRQn, (uint32_t)RTC_IRQHandler);
irq_handler = (void (*)(void))lp_ticker_irq_handler;
NVIC_SetPendingIRQ(RTC_WKUP_IRQn);
NVIC_EnableIRQ(RTC_WKUP_IRQn);
}
void rtc_deactivate_wake_up_timer(void)

View File

@ -44,31 +44,26 @@ extern "C" {
#define RTC_CLOCK LSI_VALUE
#endif
/* PREDIV_A : 7-bit asynchronous prescaler */
/* PREDIV_S : 15-bit synchronous prescaler */
/* PREDIV_S is set in order to get a 1 Hz clock */
#if DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM
/* PREDIV_A is set to a small value to improve the SubSeconds resolution */
/* with a 32768Hz clock, PREDIV_A=7 gives a precision of 244us */
#define PREDIV_A_VALUE 7
#else /* DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM */
/* PREDIV_A is set to the maximum value to improve the consumption */
#define PREDIV_A_VALUE 127
#endif /* DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM */
/* PREDIV_A : 7-bit asynchronous prescaler */
/* PREDIV_A is set to set LPTICKER frequency to RTC_CLOCK/4 */
#define PREDIV_A_VALUE 3
#define PREDIV_S_VALUE RTC_CLOCK / (PREDIV_A_VALUE + 1) - 1
/** Read RTC time with subsecond precision.
/** Read RTC counter with sub second precision
*
* @return Time is microsecond
* @return LP ticker counter
*/
uint32_t rtc_read_us(void);
uint32_t rtc_read_lp(void);
/** Program a wake up timer event in delta microseconds.
/** Program a wake up timer event
*
* @param delta The time to wait
* @param timestamp: counter to set
*/
void rtc_set_wake_up_timer(uint32_t delta);
void rtc_set_wake_up_timer(timestamp_t timestamp);
/** Call RTC Wake Up IT
*/
void rtc_fire_interrupt(void);
/** Disable the wake up timer event.
*
@ -76,13 +71,24 @@ void rtc_set_wake_up_timer(uint32_t delta);
*/
void rtc_deactivate_wake_up_timer(void);
#else /* DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM */
/* PREDIV_A : 7-bit asynchronous prescaler */
/* PREDIV_A is set to the maximum value to improve the consumption */
#define PREDIV_A_VALUE 127
#endif /* DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM */
/* PREDIV_S : 15-bit synchronous prescaler */
/* PREDIV_S is set in order to get a 1 Hz clock */
#define PREDIV_S_VALUE RTC_CLOCK / (PREDIV_A_VALUE + 1) - 1
/** Synchronise the RTC shadow registers.
*
* Must be called after a deepsleep.
*/
void rtc_synchronize(void);
#ifdef __cplusplus
}
#endif