You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by GitBox <gi...@apache.org> on 2021/08/26 18:13:04 UTC

[GitHub] [mynewt-core] kasjer commented on a change in pull request #2413: STM32 RTC based os tick

kasjer commented on a change in pull request #2413:
URL: https://github.com/apache/mynewt-core/pull/2413#discussion_r696869146



##########
File path: hw/mcu/stm/stm32_common/src/hal_os_tick.c
##########
@@ -54,6 +55,317 @@ __WFI(void)
 #endif
 #endif
 
+#if MYNEWT_VAL(OS_TICKS_USE_RTC)
+
+#if MYNEWT_VAL(STM32_CLOCK_LSE) && (((32768 / OS_TICKS_PER_SEC) * OS_TICKS_PER_SEC) != 32768)
+#error OS_TICKS_PER_SEC should be divisible by power of 2 like 128, 256, 512, 1024 when OS_TICKS_USE_RTC is enabled.
+#endif
+
+#ifndef HAL_RTC_MODULE_ENABLED
+#error Define HAL_RTC_MODULE_ENABLED in stm32[fl][0-4]xx_hal_conf.h in your bsp
+#endif
+
+#define ASYNCH_PREDIV       7
+#define SYNCH_PREDIV        (32768 / (ASYNCH_PREDIV + 1) - 1)
+#define SUB_SECONDS_BITS    12
+
+#if defined(STM32L0) || defined(STM32F0)
+#define RTC_IRQ RTC_IRQn
+#else
+#define RTC_IRQ RTC_Alarm_IRQn
+#endif
+
+#if defined(STM32L0) || defined(STM32L1)
+#define IS_RTC_ENABLED (RCC->CSR & RCC_CSR_RTCEN)
+#else
+#define IS_RTC_ENABLED (RCC->BDCR & RCC_BDCR_RTCEN)
+#endif
+
+_Static_assert(SUB_SECONDS_BITS == __builtin_popcount(SYNCH_PREDIV),
+    "SUB_SECONDS_BITS should be number of 1s in SYNCH_PREDIV");
+
+/* RTC time of the last tick. */
+static uint32_t last_rtc_time;
+static uint32_t sub_seconds_per_tick;
+static uint8_t sub_seconds_tick_bits;
+
+/* RTC holds UTC time. */
+static RTC_HandleTypeDef rtc = {
+    .Instance = RTC,
+    .Init = {
+        .HourFormat = RTC_HOURFORMAT_24,
+        .OutPut = RTC_OUTPUT_DISABLE,
+        .OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH,
+        .OutPutType = RTC_OUTPUT_TYPE_PUSHPULL,
+    }
+};
+
+/* RTC AlarmA used for OS ticks. */
+static RTC_AlarmTypeDef alarm = {
+    .AlarmTime = {
+        .Hours = 0,
+        .Minutes = 0,
+        .Seconds = 0,
+        .SubSeconds = 0,
+        .TimeFormat = RTC_HOURFORMAT12_AM,
+        .SecondFraction = 0,
+        .DayLightSaving = RTC_DAYLIGHTSAVING_NONE,
+        .StoreOperation = RTC_STOREOPERATION_RESET,
+    },
+    .AlarmMask = RTC_ALARMMASK_ALL,
+    .AlarmSubSecondMask = 0,
+    .Alarm = RTC_ALARM_A,
+};
+
+static uint32_t
+rtc_time_to_sub_seconds(const RTC_TimeTypeDef *time)
+{
+    uint32_t sub_seconds;
+
+    /* Convert sub second filed to running up sub seconds. */
+    sub_seconds = time->SecondFraction - time->SubSeconds;
+
+    sub_seconds += (((time->Hours * 60 + time->Minutes) * 60) + time->Seconds) << SUB_SECONDS_BITS;
+
+    /* Round down to ticks. */
+    sub_seconds &= ~((1 << sub_seconds_tick_bits) - 1);
+
+    return sub_seconds;
+}
+
+static void
+sub_seconds_to_rtc(uint32_t sub_seconds, RTC_TimeTypeDef *time)
+{
+    time->SubSeconds = time->SecondFraction - (sub_seconds & time->SecondFraction);
+    sub_seconds >>= SUB_SECONDS_BITS;
+    time->Seconds = sub_seconds % 60;
+    sub_seconds /= 60;
+    time->Minutes = sub_seconds % 60;
+    sub_seconds /= 60;
+    time->Hours = sub_seconds % 24;
+}
+
+static void
+rtc_update_time(void)
+{
+    int32_t delta;
+    uint32_t now;
+
+    HAL_RTC_GetTime(&rtc, &alarm.AlarmTime, RTC_FORMAT_BIN);
+    /* Get sub seconds rounded down to tick. */
+    now = rtc_time_to_sub_seconds(&alarm.AlarmTime);
+    delta = now - last_rtc_time;
+    if (delta < 0) {
+        delta += 3600 << SUB_SECONDS_BITS;
+    }
+    alarm.AlarmTime.SubSeconds = alarm.AlarmTime.SecondFraction - (now & alarm.AlarmTime.SecondFraction);
+    alarm.AlarmTime.SubSeconds -= sub_seconds_per_tick;
+    if ((int32_t)alarm.AlarmTime.SubSeconds < 0) {
+        alarm.AlarmTime.SubSeconds += alarm.AlarmTime.SecondFraction + 1;
+        alarm.AlarmTime.Seconds++;
+        if (alarm.AlarmTime.Seconds >= 60) {
+            alarm.AlarmTime.Seconds = 0;
+            alarm.AlarmTime.Minutes++;
+            if (alarm.AlarmTime.Minutes >= 60) {
+                alarm.AlarmTime.Minutes = 0;
+                if (alarm.AlarmTime.Hours >= 24) {
+                    alarm.AlarmTime.Hours = 0;
+                }
+            }
+        }
+    }
+    /* Switch to tick timer interrupt by unmasking only sub second alarm bits. */
+    alarm.AlarmMask = RTC_ALARMMASK_ALL;
+    alarm.AlarmSubSecondMask = sub_seconds_tick_bits << RTC_ALRMASSR_MASKSS_Pos;
+    HAL_RTC_SetAlarm_IT(&rtc, &alarm, RTC_FORMAT_BIN);
+
+    last_rtc_time = now;
+    os_time_advance(delta >> sub_seconds_tick_bits);
+}
+
+void
+os_tick_idle(os_time_t ticks)
+{
+    uint32_t sub_seconds;
+    OS_ASSERT_CRITICAL();
+
+    if (ticks > 0) {
+        /* Get current time directly to alarm. */
+        HAL_RTC_GetTime(&rtc, &alarm.AlarmTime, RTC_FORMAT_BIN);
+
+        alarm.AlarmSubSecondMask = SUB_SECONDS_BITS << RTC_ALRMASSR_MASKSS_Pos;
+        if (ticks < OS_TICKS_PER_SEC) {
+            /* Convert sub-seconds to up-counting value. */
+            sub_seconds = alarm.AlarmTime.SecondFraction - alarm.AlarmTime.SubSeconds;
+            /* Round down to tick. */
+            sub_seconds &= ~((1 << sub_seconds_tick_bits) - 1);
+            /* Add requested number of ticks. */
+            sub_seconds += (ticks & (OS_TICKS_PER_SEC - 1)) << sub_seconds_tick_bits;
+            /* Remove any overflow which is OK since we are sticking to 1 second limit. */
+            sub_seconds &= (1 << SUB_SECONDS_BITS) - 1;
+            /* Convert back to down-counting sub-seconds for alarm to use. */
+            alarm.AlarmTime.SubSeconds = alarm.AlarmTime.SecondFraction - sub_seconds;
+            alarm.AlarmMask = RTC_ALARMMASK_ALL;
+        } else {
+            sub_seconds = rtc_time_to_sub_seconds(&alarm.AlarmTime);
+            sub_seconds += ticks << sub_seconds_tick_bits;
+            sub_seconds_to_rtc(sub_seconds, &alarm.AlarmTime);
+            alarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY;
+        }
+        HAL_RTC_SetAlarm_IT(&rtc, &alarm, RTC_FORMAT_BIN);
+    }
+
+    __DSB();
+    __WFI();
+
+    if (ticks > 0) {
+        rtc_update_time();
+    }
+}
+
+/* ST HAL interrupt handler calls this function. */
+void
+HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
+{
+    (void)hrtc;
+    rtc_update_time();
+}
+
+void
+RTC_Alarm_IRQHandler(void)
+{
+    int sr;
+
+    os_trace_isr_enter();
+
+    OS_ENTER_CRITICAL(sr);
+    HAL_RTC_AlarmIRQHandler(&rtc);
+    OS_EXIT_CRITICAL(sr);
+
+    os_trace_isr_exit();
+}
+
+static void
+stm32_rtc_os_time_change(const struct os_time_change_info *info, void *arg)
+{
+    struct clocktime ct;
+    RTC_DateTypeDef date;
+    uint32_t sub_seconds;
+    int sr;
+
+    timeval_to_clocktime(info->tci_cur_tv, NULL, &ct);
+    date.Year = ct.year - 2000;
+    date.Month = ct.mon;
+    date.Date = ct.day;
+    /* ST HAL Sunday is 7. */
+    date.WeekDay = ct.dow ? ct.dow : 7;
+    sub_seconds = ct.usec * 64 / 15625;
+
+    OS_ENTER_CRITICAL(sr);
+
+    alarm.AlarmTime.Hours = ct.hour;
+    alarm.AlarmTime.Minutes = ct.min;
+    alarm.AlarmTime.Seconds = ct.sec;
+    alarm.AlarmTime.SubSeconds = alarm.AlarmTime.SecondFraction;
+
+    HAL_RTC_SetTime(&rtc, &alarm.AlarmTime, RTC_FORMAT_BIN);
+    HAL_RTC_SetDate(&rtc, &date, RTC_FORMAT_BIN);
+    if (sub_seconds) {
+        RTC->SHIFTR = RTC_SHIFTR_ADD1S | sub_seconds;
+    }
+    last_rtc_time = rtc_time_to_sub_seconds(&alarm.AlarmTime);
+    alarm.AlarmTime.SubSeconds -= sub_seconds_per_tick;
+    alarm.AlarmMask = RTC_ALARMMASK_ALL;
+    HAL_RTC_SetAlarm_IT(&rtc, &alarm, RTC_FORMAT_BIN);
+
+    OS_EXIT_CRITICAL(sr);
+}
+
+static struct os_time_change_listener rtc_setter = {
+    .tcl_fn = stm32_rtc_os_time_change,
+};
+
+static void
+set_os_datetime_from_rtc(const RTC_TimeTypeDef *time, const RTC_DateTypeDef *date)
+{
+    struct os_timeval utc;
+    struct clocktime ct;
+    ct.year = 2000 + date->Year;
+    ct.mon = date->Month;
+    ct.day = date->Date;
+    ct.dow = date->WeekDay == 7 ? 0 : date->WeekDay;
+    ct.hour = time->Hours;
+    ct.min = time->Minutes;
+    ct.sec = time->Seconds;
+    ct.usec = ((time->SecondFraction - time->SubSeconds) * 15625) >> SUB_SECONDS_BITS;

Review comment:
       excellent point, it should be 1000000




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@mynewt.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org