From 68da5e845a10bd66e49f14d2b6c1d1764195db06 Mon Sep 17 00:00:00 2001 From: Giovanni Di Sirio Date: Sat, 19 Oct 2019 07:36:15 +0000 Subject: [PATCH] New RTCv3 driver for STM32G0xx and STM32G4xx. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@13116 27425a3e-05d8-49a3-a47f-9c15f0e5edd8 --- .../RT-STM32G071RB-NUCLEO64/cfg/mcuconf.h | 9 +- os/hal/ports/STM32/LLD/RTCv3/driver.mk | 9 + os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.c | 665 ++++++++++++++++++ os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.h | 285 ++++++++ os/hal/ports/STM32/STM32G0xx/platform.mk | 2 +- os/hal/ports/STM32/STM32G0xx/stm32_registry.h | 19 +- os/hal/ports/STM32/STM32G4xx/platform.mk | 2 +- readme.txt | 1 + .../conf/mcuconf_stm32g071xx/mcuconf.h.ftl | 3 +- 9 files changed, 982 insertions(+), 13 deletions(-) create mode 100644 os/hal/ports/STM32/LLD/RTCv3/driver.mk create mode 100644 os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.c create mode 100644 os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.h diff --git a/demos/STM32/RT-STM32G071RB-NUCLEO64/cfg/mcuconf.h b/demos/STM32/RT-STM32G071RB-NUCLEO64/cfg/mcuconf.h index ae975d75b..c444c1690 100644 --- a/demos/STM32/RT-STM32G071RB-NUCLEO64/cfg/mcuconf.h +++ b/demos/STM32/RT-STM32G071RB-NUCLEO64/cfg/mcuconf.h @@ -80,13 +80,14 @@ /* * Shared IRQ settings. */ -#define STM32_IRQ_EXTI0_1_PRIORITY 2 -#define STM32_IRQ_EXTI2_3_PRIORITY 2 -#define STM32_IRQ_EXTI4_15_PRIORITY 2 +#define STM32_IRQ_EXTI0_1_PRIORITY 3 +#define STM32_IRQ_EXTI2_3_PRIORITY 3 +#define STM32_IRQ_EXTI4_15_PRIORITY 3 +#define STM32_IRQ_EXTI1921_PRIORITY 3 #define STM32_IRQ_USART1_PRIORITY 2 #define STM32_IRQ_USART2_PRIORITY 2 -#define STM32_IRQ_USART3_4_LP1_PRIORITY 1 +#define STM32_IRQ_USART3_4_LP1_PRIORITY 2 #define STM32_IRQ_TIM1_UP_PRIORITY 1 #define STM32_IRQ_TIM1_CC_PRIORITY 1 diff --git a/os/hal/ports/STM32/LLD/RTCv3/driver.mk b/os/hal/ports/STM32/LLD/RTCv3/driver.mk new file mode 100644 index 000000000..be3a5ad06 --- /dev/null +++ b/os/hal/ports/STM32/LLD/RTCv3/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_RTC TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv3 diff --git a/os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.c b/os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.c new file mode 100644 index 000000000..2e8b2908b --- /dev/null +++ b/os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.c @@ -0,0 +1,665 @@ +/* + ChibiOS - Copyright (C) 2006..2019 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +/* + Concepts and parts of this file have been contributed by Uladzimir Pylinsky + aka barthess. + */ + +/** + * @file RTCv3/hal_rtc_lld.c + * @brief STM32 RTC low level driver. + * + * @addtogroup RTC + * @{ + */ + +#include "hal.h" + +#if HAL_USE_RTC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define RTC_TR_PM_OFFSET RTC_TR_PM_Pos +#define RTC_TR_HT_OFFSET RTC_TR_HT_Pos +#define RTC_TR_HU_OFFSET RTC_TR_HU_Pos +#define RTC_TR_MNT_OFFSET RTC_TR_MNT_Pos +#define RTC_TR_MNU_OFFSET RTC_TR_MNU_Pos +#define RTC_TR_ST_OFFSET RTC_TR_ST_Pos +#define RTC_TR_SU_OFFSET RTC_TR_SU_Pos + +#define RTC_DR_YT_OFFSET RTC_DR_YT_Pos +#define RTC_DR_YU_OFFSET RTC_DR_YU_Pos +#define RTC_DR_WDU_OFFSET RTC_DR_WDU_Pos +#define RTC_DR_MT_OFFSET RTC_DR_MT_Pos +#define RTC_DR_MU_OFFSET RTC_DR_MU_Pos +#define RTC_DR_DT_OFFSET RTC_DR_DT_Pos +#define RTC_DR_DU_OFFSET RTC_DR_DU_Pos + +#define RTC_CR_BKP_OFFSET RTC_CR_BKP_Pos + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief RTC driver identifier. + */ +RTCDriver RTCD1; + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Beginning of configuration procedure. + * + * @notapi + */ +static void rtc_enter_init(void) { + + RTCD1.rtc->ICSR |= RTC_ICSR_INIT; + while ((RTCD1.rtc->ICSR & RTC_ICSR_INITF) == 0) + ; +} + +/** + * @brief Finalizing of configuration procedure. + * + * @notapi + */ +static inline void rtc_exit_init(void) { + + RTCD1.rtc->ICSR &= ~RTC_ICSR_INIT; +} + +/** + * @brief Converts time from TR register encoding to timespec. + * + * @param[in] tr TR register value + * @param[out] timespec pointer to a @p RTCDateTime structure + * + * @notapi + */ +static void rtc_decode_time(uint32_t tr, RTCDateTime *timespec) { + uint32_t n; + + n = ((tr >> RTC_TR_HT_OFFSET) & 3) * 36000000; + n += ((tr >> RTC_TR_HU_OFFSET) & 15) * 3600000; + n += ((tr >> RTC_TR_MNT_OFFSET) & 7) * 600000; + n += ((tr >> RTC_TR_MNU_OFFSET) & 15) * 60000; + n += ((tr >> RTC_TR_ST_OFFSET) & 7) * 10000; + n += ((tr >> RTC_TR_SU_OFFSET) & 15) * 1000; + timespec->millisecond = n; +} + +/** + * @brief Converts date from DR register encoding to timespec. + * + * @param[in] dr DR register value + * @param[out] timespec pointer to a @p RTCDateTime structure + * + * @notapi + */ +static void rtc_decode_date(uint32_t dr, RTCDateTime *timespec) { + + timespec->year = (((dr >> RTC_DR_YT_OFFSET) & 15) * 10) + + ((dr >> RTC_DR_YU_OFFSET) & 15); + timespec->month = (((dr >> RTC_TR_MNT_OFFSET) & 1) * 10) + + ((dr >> RTC_TR_MNU_OFFSET) & 15); + timespec->day = (((dr >> RTC_DR_DT_OFFSET) & 3) * 10) + + ((dr >> RTC_DR_DU_OFFSET) & 15); + timespec->dayofweek = ((dr >> RTC_DR_WDU_OFFSET) & 7) + 1; +} + +/** + * @brief Converts time from timespec to TR register encoding. + * + * @param[in] timespec pointer to a @p RTCDateTime structure + * @return the TR register encoding. + * + * @notapi + */ +static uint32_t rtc_encode_time(const RTCDateTime *timespec) { + uint32_t n, tr = 0; + + /* Subseconds cannot be set.*/ + n = timespec->millisecond / 1000; + + /* Seconds conversion.*/ + tr = tr | ((n % 10) << RTC_TR_SU_OFFSET); + n /= 10; + tr = tr | ((n % 6) << RTC_TR_ST_OFFSET); + n /= 6; + + /* Minutes conversion.*/ + tr = tr | ((n % 10) << RTC_TR_MNU_OFFSET); + n /= 10; + tr = tr | ((n % 6) << RTC_TR_MNT_OFFSET); + n /= 6; + + /* Hours conversion.*/ + tr = tr | ((n % 10) << RTC_TR_HU_OFFSET); + n /= 10; + tr = tr | (n << RTC_TR_HT_OFFSET); + + return tr; +} + +/** + * @brief Converts a date from timespec to DR register encoding. + * + * @param[in] timespec pointer to a @p RTCDateTime structure + * @return the DR register encoding. + * + * @notapi + */ +static uint32_t rtc_encode_date(const RTCDateTime *timespec) { + uint32_t n, dr = 0; + + /* Year conversion. Note, only years last two digits are considered.*/ + n = timespec->year; + dr = dr | ((n % 10) << RTC_DR_YU_OFFSET); + n /= 10; + dr = dr | ((n % 10) << RTC_DR_YT_OFFSET); + + /* Months conversion.*/ + n = timespec->month; + dr = dr | ((n % 10) << RTC_DR_MU_OFFSET); + n /= 10; + dr = dr | ((n % 10) << RTC_DR_MT_OFFSET); + + /* Days conversion.*/ + n = timespec->day; + dr = dr | ((n % 10) << RTC_DR_DU_OFFSET); + n /= 10; + dr = dr | ((n % 10) << RTC_DR_DT_OFFSET); + + /* Days of week conversion.*/ + dr = dr | ((timespec->dayofweek) << RTC_DR_WDU_OFFSET); + + return dr; +} + +#if RTC_HAS_STORAGE == TRUE +static size_t _getsize(void *instance) { + + (void)instance; + + return (size_t)STM32_RTC_STORAGE_SIZE; +} + +static ps_error_t _read(void *instance, ps_offset_t offset, + size_t n, uint8_t *rp) { + volatile uint32_t *bkpr = &((RTCDriver *)instance)->tamp->BKP0R; + unsigned i; + + chDbgCheck((instance != NULL) && (rp != NULL)); + chDbgCheck((n > 0U) && (n <= STM32_RTC_STORAGE_SIZE)); + chDbgCheck((offset < STM32_RTC_STORAGE_SIZE) && + (offset + n <= STM32_RTC_STORAGE_SIZE)); + + for (i = 0; i < (unsigned)n; i++) { + unsigned index = ((unsigned)offset + i) / sizeof (uint32_t); + unsigned shift = ((unsigned)offset + i) % sizeof (uint32_t); + *rp++ = (uint8_t)(bkpr[index] >> (shift * 8U)); + } + + return PS_NO_ERROR; +} + +static ps_error_t _write(void *instance, ps_offset_t offset, + size_t n, const uint8_t *wp) { + volatile uint32_t *bkpr = &((RTCDriver *)instance)->tamp->BKP0R; + unsigned i; + + chDbgCheck((instance != NULL) && (wp != NULL)); + chDbgCheck((n > 0U) && (n <= STM32_RTC_STORAGE_SIZE)); + chDbgCheck((offset < STM32_RTC_STORAGE_SIZE) && + (offset + n <= STM32_RTC_STORAGE_SIZE)); + + for (i = 0; i < (unsigned)n; i++) { + unsigned index = ((unsigned)offset + i) / sizeof (uint32_t); + unsigned shift = ((unsigned)offset + i) % sizeof (uint32_t); + uint32_t regval = bkpr[index]; + regval &= ~(0xFFU << (shift * 8U)); + regval |= (uint32_t)*wp++ << (shift * 8U); + bkpr[index] = regval; + } + + return PS_NO_ERROR; +} + +/** + * @brief VMT for the RTC storage file interface. + */ +struct RTCDriverVMT _rtc_lld_vmt = { + (size_t)0, + _getsize, _read, _write +}; +#endif /* RTC_HAS_STORAGE == TRUE */ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if defined(STM32_RTC_COMMON_HANDLER) +#if !defined(STM32_RTC_SUPPRESS_COMMON_ISR) +/** + * @brief RTC common interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_RTC_COMMON_HANDLER) { + uint32_t isr; + + OSAL_IRQ_PROLOGUE(); + + /* Get the interrupt events. */ + isr = RTCD1.rtc->MISR; + RTCD1.rtc->SCR = isr; + extiClearGroup1(EXTI_MASK1(STM32_RTC_EVENT_EXTI) | + EXTI_MASK1(STM32_TAMP_EVENT_EXTI)); + + if (RTCD1.callback != NULL) { + +#if defined(RTC_MISR_WUTMF) + if ((isr & RTC_MISR_WUTMF) != 0U) { + RTCD1.callback(&RTCD1, RTC_EVENT_WAKEUP); + } +#endif + +#if defined(RTC_MISR_ALRAMF) + if ((isr & RTC_MISR_ALRAMF) != 0U) { + RTCD1.callback(&RTCD1, RTC_EVENT_ALARM_A); + } +#endif +#if defined(RTC_MISR_ALRBMF) + if ((isr & RTC_MISR_ALRBMF) != 0U) { + RTCD1.callback(&RTCD1, RTC_EVENT_ALARM_B); + } +#endif +#if defined(RTC_MISR_ITSMF) + if ((isr & RTC_MISR_ITSMF) != 0U) { + RTCD1.callback(&RTCD1, RTC_EVENT_TS); + } +#endif +#if defined(RTC_MISR_TSOVMF) + if ((isr & RTC_MISR_TSOVMF) != 0U) { + RTCD1.callback(&RTCD1, RTC_EVENT_TS_OVF); + } +#endif + + /* Next handle the tamper interrupts. */ + isr = RTCD1.tamp->MISR; + RTCD1.tamp->SCR = isr; +#if defined(TAMP_MISR_TAMP1MF) + if ((isr & TAMP_MISR_TAMP1MF) != 0U) { + RTCD1.callback(&RTCD1, RTC_EVENT_TAMP1); + } +#endif +#if defined(TAMP_MISR_TAMP2MF) + if ((isr & TAMP_MISR_TAMP2MF) != 0U) { + RTCD1.callback(&RTCD1, RTC_EVENT_TAMP2); + } +#endif +#if defined(TAMP_MISR_TAMP3MF) + if ((isr & TAMP_MISR_TAMP3MF) != 0U) { + RTCD1.callback(&RTCD1, RTC_EVENT_TAMP3); + } +#endif +#if defined(TAMP_MISR_TAMP4MF) + if ((isr & TAMP_MISR_TAMP4MF) != 0U) { + RTCD1.callback(&RTCD1, RTC_EVENT_TAMP4); + } +#endif +#if defined(TAMP_MISR_TAMP5MF) + if ((isr & TAMP_MISR_TAMP5MF) != 0U) { + RTCD1.callback(&RTCD1, RTC_EVENT_TAMP5); + } +#endif +#if defined(TAMP_MISR_TAMP6MF) + if ((isr & TAMP_MISR_TAMP6MF) != 0U) { + RTCD1.callback(&RTCD1, RTC_EVENT_TAMP6); + } +#endif + } + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_RTC_SUPPRESS_COMMON_ISR) */ + +#else +#error "missing required RTC handlers definitions in registry" +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Enable access to registers. + * + * @notapi + */ +void rtc_lld_init(void) { + + /* RTC object initialization.*/ + rtcObjectInit(&RTCD1); + + /* RTC pointer initialization.*/ + RTCD1.rtc = RTC; + + /* Disable write protection. */ + RTCD1.rtc->WPR = 0xCA; + RTCD1.rtc->WPR = 0x53; + + /* If calendar has not been initialized yet then proceed with the + initial setup.*/ + if (!(RTCD1.rtc->ICSR & RTC_ICSR_INITS)) { + + rtc_enter_init(); + + RTCD1.rtc->CR |= (STM32_RTC_CR_INIT & STM32_RTC_CR_MASK); + RTCD1.rtc->ICSR |= RTC_ICSR_INIT; /* Clearing all but RTC_ISR_INIT. */ + RTCD1.rtc->PRER |= (STM32_RTC_PRER_BITS & STM32_RTC_PRER_MASK); + + rtc_exit_init(); + } + else { + RTCD1.rtc->ICSR &= ~RTC_ICSR_RSF; + } + + + /* TAMP pointer initialization. */ + RTCD1.tamp = TAMP; + + /* Initialise TAMP registers. */ + RTCD1.tamp->CR1 |= (STM32_TAMP_CR1_INIT & STM32_TAMP_CR1_MASK); + RTCD1.tamp->CR2 |= (STM32_TAMP_CR2_INIT & STM32_TAMP_CR2_MASK); + RTCD1.tamp->FLTCR |= (STM32_TAMP_FLTCR_INIT & STM32_TAMP_FLTCR_MASK); + RTCD1.tamp->IER |= (STM32_TAMP_IER_INIT & STM32_TAMP_IER_MASK); + + /* Callback initially disabled.*/ + RTCD1.callback = NULL; + + /* Enabling RTC-related EXTI lines.*/ + + extiEnableGroup1(EXTI_MASK1(STM32_RTC_EVENT_EXTI) | + EXTI_MASK1(STM32_TAMP_EVENT_EXTI), + EXTI_MODE_RISING_EDGE | EXTI_MODE_ACTION_INTERRUPT); + /* The EXTI lines are direct. Events enabled by peripheral + and trigger on their rising edge only */ + + /* IRQ vectors permanently assigned to this driver.*/ + STM32_RTC_AND_TAMP_IRQ_ENABLE(); +} + +/** + * @brief Set current time. + * @note Fractional part will be silently ignored. There is no possibility + * to set it on STM32 platform. + * @note The function can be called from any context. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[in] timespec pointer to a @p RTCDateTime structure + * + * @notapi + */ +void rtc_lld_set_time(RTCDriver *rtcp, const RTCDateTime *timespec) { + uint32_t dr, tr; + syssts_t sts; + + tr = rtc_encode_time(timespec); + dr = rtc_encode_date(timespec); + + /* Entering a reentrant critical zone.*/ + sts = osalSysGetStatusAndLockX(); + + /* Writing the registers.*/ + rtc_enter_init(); + rtcp->rtc->TR = tr; + rtcp->rtc->DR = dr; + rtcp->rtc->CR = (rtcp->rtc->CR & ~(1U << RTC_CR_BKP_OFFSET)) | + (timespec->dstflag << RTC_CR_BKP_OFFSET); + rtc_exit_init(); + + /* Leaving a reentrant critical zone.*/ + osalSysRestoreStatusX(sts); +} + +/** + * @brief Get current time. + * @note The function can be called from any context. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[out] timespec pointer to a @p RTCDateTime structure + * + * @notapi + */ +void rtc_lld_get_time(RTCDriver *rtcp, RTCDateTime *timespec) { + uint32_t dr, tr, cr; + uint32_t subs; +#if STM32_RTC_HAS_SUBSECONDS + uint32_t ssr; +#endif /* STM32_RTC_HAS_SUBSECONDS */ + syssts_t sts; + + /* Entering a reentrant critical zone.*/ + sts = osalSysGetStatusAndLockX(); + + /* Synchronization with the RTC and reading the registers, note + DR must be read last.*/ + while ((rtcp->rtc->ICSR & RTC_ICSR_RSF) == 0) + ; +#if STM32_RTC_HAS_SUBSECONDS + ssr = rtcp->rtc->SSR; +#endif /* STM32_RTC_HAS_SUBSECONDS */ + tr = rtcp->rtc->TR; + dr = rtcp->rtc->DR; + cr = rtcp->rtc->CR; + rtcp->rtc->ICSR &= ~RTC_ICSR_RSF; + + /* Leaving a reentrant critical zone.*/ + osalSysRestoreStatusX(sts); + + /* Decoding day time, this starts the atomic read sequence, see "Reading + the calendar" in the RTC documentation.*/ + rtc_decode_time(tr, timespec); + + /* If the RTC is capable of sub-second counting then the value is + normalized in milliseconds and added to the time.*/ +#if STM32_RTC_HAS_SUBSECONDS + subs = (((STM32_RTC_PRESS_VALUE - 1U) - ssr) * 1000U) / STM32_RTC_PRESS_VALUE; +#else + subs = 0; +#endif /* STM32_RTC_HAS_SUBSECONDS */ + timespec->millisecond += subs; + + /* Decoding date, this concludes the atomic read sequence.*/ + rtc_decode_date(dr, timespec); + + /* Retrieving the DST bit.*/ + timespec->dstflag = (cr >> RTC_CR_BKP_OFFSET) & 1; +} + +#if (RTC_ALARMS > 0) || defined(__DOXYGEN__) +/** + * @brief Set alarm time. + * @note Default value after BKP domain reset for both comparators is 0. + * @note Function does not performs any checks of alarm time validity. + * @note The function can be called from any context. + * + * @param[in] rtcp pointer to RTC driver structure. + * @param[in] alarm alarm identifier. Can be 0 (=1), 1 or 2. + * @param[in] alarmspec pointer to a @p RTCAlarm structure. + * + * @notapi + */ +void rtc_lld_set_alarm(RTCDriver *rtcp, + rtcalarm_t alarm, + const RTCAlarm *alarmspec) { + syssts_t sts; + + /* Entering a reentrant critical zone.*/ + sts = osalSysGetStatusAndLockX(); + + if (alarm == 0) { + if (alarmspec != NULL) { + rtcp->rtc->CR &= ~RTC_CR_ALRAE; + while (!(rtcp->rtc->ICSR & RTC_ICSR_ALRAWF)) + ; + rtcp->rtc->ALRMAR = alarmspec->alrmr; + rtcp->rtc->CR |= RTC_CR_ALRAE; + rtcp->rtc->CR |= RTC_CR_ALRAIE; + } + else { + rtcp->rtc->CR &= ~RTC_CR_ALRAIE; + rtcp->rtc->CR &= ~RTC_CR_ALRAE; + } + } +#if RTC_ALARMS > 1 + else { + if (alarmspec != NULL) { + rtcp->rtc->CR &= ~RTC_CR_ALRBE; + while (!(rtcp->rtc->ICSR & RTC_ICSR_ALRBWF)) + ; + rtcp->rtc->ALRMBR = alarmspec->alrmr; + rtcp->rtc->CR |= RTC_CR_ALRBE; + rtcp->rtc->CR |= RTC_CR_ALRBIE; + } + else { + rtcp->rtc->CR &= ~RTC_CR_ALRBIE; + rtcp->rtc->CR &= ~RTC_CR_ALRBE; + } + } +#endif /* RTC_ALARMS > 1 */ + + /* Leaving a reentrant critical zone.*/ + osalSysRestoreStatusX(sts); +} + +/** + * @brief Get alarm time. + * @note The function can be called from any context. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[in] alarm alarm identifier. Can be 0 (=1), 1 or 2. + * @param[out] alarmspec pointer to a @p RTCAlarm structure + * + * @notapi + */ +void rtc_lld_get_alarm(RTCDriver *rtcp, + rtcalarm_t alarm, + RTCAlarm *alarmspec) { + + if (alarm == 0) + alarmspec->alrmr = rtcp->rtc->ALRMAR; +#if RTC_ALARMS > 1 + else + alarmspec->alrmr = rtcp->rtc->ALRMBR; +#endif /* RTC_ALARMS > 1 */ +} +#endif /* RTC_ALARMS > 0 */ + +/** + * @brief Enables or disables RTC callbacks. + * @details This function enables or disables callbacks, use a @p NULL pointer + * in order to disable a callback. + * @note The function can be called from any context. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[in] callback callback function pointer or @p NULL + * + * @notapi + */ +void rtc_lld_set_callback(RTCDriver *rtcp, rtccb_t callback) { + + rtcp->callback = callback; +} + +#if STM32_RTC_HAS_PERIODIC_WAKEUPS || defined(__DOXYGEN__) +/** + * @brief Sets time of periodic wakeup. + * @note Default value after BKP domain reset is 0x0000FFFF + * @note The function can be called from any context. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[in] wakeupspec pointer to a @p RTCWakeup structure + * + * @api + */ +void rtcSTM32SetPeriodicWakeup(RTCDriver *rtcp, const RTCWakeup *wakeupspec) { + syssts_t sts; + + /* Entering a reentrant critical zone.*/ + sts = osalSysGetStatusAndLockX(); + + if (wakeupspec != NULL) { + osalDbgCheck(wakeupspec->wutr != 0x30000); + + rtcp->rtc->CR &= ~RTC_CR_WUTE; + rtcp->rtc->CR &= ~RTC_CR_WUTIE; + while (!(rtcp->rtc->ICSR & RTC_ICSR_WUTWF)) + ; + rtcp->rtc->WUTR = wakeupspec->wutr & 0xFFFF; + rtcp->rtc->CR &= ~RTC_CR_WUCKSEL; + rtcp->rtc->CR |= (wakeupspec->wutr >> 16) & RTC_CR_WUCKSEL; + rtcp->rtc->CR |= RTC_CR_WUTIE; + rtcp->rtc->CR |= RTC_CR_WUTE; + } + else { + rtcp->rtc->CR &= ~RTC_CR_WUTE; + rtcp->rtc->CR &= ~RTC_CR_WUTIE; + } + + /* Leaving a reentrant critical zone.*/ + osalSysRestoreStatusX(sts); +} + +/** + * @brief Gets time of periodic wakeup. + * @note Default value after BKP domain reset is 0x0000FFFF + * @note The function can be called from any context. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[out] wakeupspec pointer to a @p RTCWakeup structure + * + * @api + */ +void rtcSTM32GetPeriodicWakeup(RTCDriver *rtcp, RTCWakeup *wakeupspec) { + syssts_t sts; + + /* Entering a reentrant critical zone.*/ + sts = osalSysGetStatusAndLockX(); + + wakeupspec->wutr = 0; + wakeupspec->wutr |= rtcp->rtc->WUTR; + wakeupspec->wutr |= (((uint32_t)rtcp->rtc->CR) & 0x7) << 16; + + /* Leaving a reentrant critical zone.*/ + osalSysRestoreStatusX(sts); +} +#endif /* STM32_RTC_HAS_PERIODIC_WAKEUPS */ + +#endif /* HAL_USE_RTC */ + +/** @} */ diff --git a/os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.h b/os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.h new file mode 100644 index 000000000..da68cb5be --- /dev/null +++ b/os/hal/ports/STM32/LLD/RTCv3/hal_rtc_lld.h @@ -0,0 +1,285 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +/* + Concepts and parts of this file have been contributed by Uladzimir Pylinsky + aka barthess. + */ + +/** + * @file RTCv3/hal_rtc_lld.h + * @brief STM32 RTC low level driver header. + * + * @addtogroup RTC + * @{ + */ + +#ifndef HAL_RTC_LLD_H +#define HAL_RTC_LLD_H + +#if HAL_USE_RTC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name Implementation capabilities + */ +/** + * @brief Callback support int the driver. + */ +#define RTC_SUPPORTS_CALLBACKS TRUE + +/** + * @brief Number of alarms available. + */ +#define RTC_ALARMS STM32_RTC_NUM_ALARMS + +/** + * @brief Presence of a local persistent storage. + */ +#define RTC_HAS_STORAGE (STM32_RTC_STORAGE_SIZE > 0) +/** @} */ + +/** + * @brief RTC PRER register initializer. + */ +#define RTC_PRER(a, s) ((((a) - 1) << 16) | ((s) - 1)) + +/** + * @name Alarm helper macros + * @{ + */ +#define RTC_ALRM_MSK4 (1U << 31) +#define RTC_ALRM_WDSEL (1U << 30) +#define RTC_ALRM_DT(n) ((n) << 28) +#define RTC_ALRM_DU(n) ((n) << 24) +#define RTC_ALRM_MSK3 (1U << 23) +#define RTC_ALRM_HT(n) ((n) << 20) +#define RTC_ALRM_HU(n) ((n) << 16) +#define RTC_ALRM_MSK2 (1U << 15) +#define RTC_ALRM_MNT(n) ((n) << 12) +#define RTC_ALRM_MNU(n) ((n) << 8) +#define RTC_ALRM_MSK1 (1U << 7) +#define RTC_ALRM_ST(n) ((n) << 4) +#define RTC_ALRM_SU(n) ((n) << 0) +/** @} */ + +/* Requires services from the EXTI driver.*/ +#if !defined(STM32_EXTI_REQUIRED) +#define STM32_EXTI_REQUIRED +#endif + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief RTC PRES register initialization. + * @note The default is calculated for a 32768Hz clock. + */ +#if !defined(STM32_RTC_PRESA_VALUE) || defined(__DOXYGEN__) +#define STM32_RTC_PRESA_VALUE 32 +#endif + +/** + * @brief RTC PRESS divider initialization. + * @note The default is calculated for a 32768Hz clock. + */ +#if !defined(STM32_RTC_PRESS_VALUE) || defined(__DOXYGEN__) +#define STM32_RTC_PRESS_VALUE 1024 +#endif + +/** + * @brief RTC CR register initialization value. + * @note Use this value to initialize features not directly handled by + * the RTC driver. + */ +#if !defined(STM32_RTC_CR_INIT) || defined(__DOXYGEN__) +#define STM32_RTC_CR_INIT 0 +#endif + +/** + * @brief TAMP register initialization value. + * @note Use this value to initialize features not directly handled by + * the RTC driver. + * @note On some devices this values goes in the similar TAFCR register. + */ +#if !defined(STM32_TAMP_CR1_INIT) || defined(__DOXYGEN__) +#define STM32_TAMP_CR1_INIT 0 +#endif + +/** + * @brief TAMP register initialization value. + * @note Use this value to initialize features not directly handled by + * the RTC driver. + * @note On some devices this values goes in the similar TAFCR register. + */ +#if !defined(STM32_TAMP_CR2_INIT) || defined(__DOXYGEN__) +#define STM32_TAMP_CR2_INIT 0 +#endif + +/** + * @brief TAMP register initialization value. + * @note Use this value to initialize features not directly handled by + * the RTC driver. + * @note On some devices this values goes in the similar TAFCR register. + */ +#if !defined(STM32_TAMP_FLTCR_INIT) || defined(__DOXYGEN__) +#define STM32_TAMP_FLTCR_INIT 0 +#endif + +/** + * @brief TAMP register initialization value. + * @note Use this value to initialize features not directly handled by + * the RTC driver. + * @note On some devices this values goes in the similar TAFCR register. + */ +#if !defined(STM32_TAMP_IER_INIT) || defined(__DOXYGEN__) +#define STM32_TAMP_IER_INIT 0 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if HAL_USE_RTC && !STM32_HAS_RTC +#error "RTC not present in the selected device" +#endif + +#if defined(STM32_RTC_CK) && !defined(STM32_RTCCLK) +#define STM32_RTCCLK STM32_RTC_CK +#endif + +#if !defined(STM32_RTCCLK) +#error "RTC clock not exported by HAL layer" +#endif + +#if STM32_PCLK1 < (STM32_RTCCLK * 7) +#error "STM32_PCLK1 frequency is too low" +#endif + +/** + * @brief Initialization for the RTC_PRER register. + */ +#define STM32_RTC_PRER_BITS RTC_PRER(STM32_RTC_PRESA_VALUE, \ + STM32_RTC_PRESS_VALUE) + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of an RTC event. + */ +typedef enum { + RTC_EVENT_ALARM_A = 0, /** Alarm A. */ + RTC_EVENT_ALARM_B = 1, /** Alarm B. */ + RTC_EVENT_TS = 2, /** Time stamp. */ + RTC_EVENT_TS_OVF = 3, /** Time stamp overflow. */ + RTC_EVENT_TAMP1 = 4, /** Tamper 1. */ + RTC_EVENT_TAMP2 = 5, /** Tamper 2- */ + RTC_EVENT_TAMP3 = 6, /** Tamper 3. */ + RTC_EVENT_TAMP4 = 7, /** Tamper 4. */ + RTC_EVENT_TAMP5 = 8, /** Tamper 5. */ + RTC_EVENT_TAMP6 = 9, /** Tamper 6. */ + RTC_EVENT_WAKEUP = 10, /** Wakeup. */ + } rtcevent_t; + +/** + * @brief Type of a generic RTC callback. + */ +typedef void (*rtccb_t)(RTCDriver *rtcp, rtcevent_t event); + +/** + * @brief Type of a structure representing an RTC alarm time stamp. + */ +typedef struct hal_rtc_alarm { + /** + * @brief Type of an alarm as encoded in RTC ALRMxR registers. + */ + uint32_t alrmr; +} RTCAlarm; + +#if STM32_RTC_HAS_PERIODIC_WAKEUPS +/** + * @brief Type of a wakeup as encoded in RTC WUTR register. + */ +typedef struct hal_rtc_wakeup { + /** + * @brief Wakeup as encoded in RTC WUTR register. + * @note ((WUTR == 0) || (WUCKSEL == 3)) are a forbidden combination. + * @note Bits 16..18 are copied in the CR bits 0..2 (WUCKSEL). + */ + uint32_t wutr; +} RTCWakeup; +#endif + +/** + * @brief Implementation-specific @p RTCDriver fields. + */ +#define rtc_lld_driver_fields \ + /* Pointer to the RTC registers block.*/ \ + RTC_TypeDef *rtc; \ + /* RTC event callback pointer.*/ \ + rtccb_t callback; \ + /* Pointer to TAMPER registers block. */ \ + TAMP_TypeDef *tamp + + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void rtc_lld_init(void); + void rtc_lld_set_time(RTCDriver *rtcp, const RTCDateTime *timespec); + void rtc_lld_get_time(RTCDriver *rtcp, RTCDateTime *timespec); +#if RTC_SUPPORTS_CALLBACKS == TRUE + void rtc_lld_set_callback(RTCDriver *rtcp, rtccb_t callback); +#endif +#if RTC_ALARMS > 0 + void rtc_lld_set_alarm(RTCDriver *rtcp, + rtcalarm_t alarm, + const RTCAlarm *alarmspec); + void rtc_lld_get_alarm(RTCDriver *rtcp, + rtcalarm_t alarm, + RTCAlarm *alarmspec); +#endif +#if STM32_RTC_HAS_PERIODIC_WAKEUPS + void rtcSTM32SetPeriodicWakeup(RTCDriver *rtcp, const RTCWakeup *wakeupspec); + void rtcSTM32GetPeriodicWakeup(RTCDriver *rtcp, RTCWakeup *wakeupspec); +#endif /* STM32_RTC_HAS_PERIODIC_WAKEUPS */ +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_RTC */ + +#endif /* HAL_RTC_LLD_H */ + +/** @} */ diff --git a/os/hal/ports/STM32/STM32G0xx/platform.mk b/os/hal/ports/STM32/STM32G0xx/platform.mk index cf639dec4..77cfedd42 100644 --- a/os/hal/ports/STM32/STM32G0xx/platform.mk +++ b/os/hal/ports/STM32/STM32G0xx/platform.mk @@ -32,7 +32,7 @@ include $(CHIBIOS)/os/hal/ports/STM32/LLD/DMAv1/driver.mk include $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1/driver.mk include $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv2/driver.mk include $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv2/driver.mk -#include $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv2/driver.mk +include $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv3/driver.mk include $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv2/driver.mk include $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/driver.mk include $(CHIBIOS)/os/hal/ports/STM32/LLD/USARTv2/driver.mk diff --git a/os/hal/ports/STM32/STM32G0xx/stm32_registry.h b/os/hal/ports/STM32/STM32G0xx/stm32_registry.h index f9f51657f..6e9682acc 100644 --- a/os/hal/ports/STM32/STM32G0xx/stm32_registry.h +++ b/os/hal/ports/STM32/STM32G0xx/stm32_registry.h @@ -38,7 +38,7 @@ /* Common. */ /*===========================================================================*/ -/* RTC attributes.*/ +/* RTC and TAMP attributes.*/ #define STM32_HAS_RTC TRUE #define STM32_RTC_HAS_SUBSECONDS TRUE #define STM32_RTC_HAS_PERIODIC_WAKEUPS TRUE @@ -46,14 +46,21 @@ #define STM32_RTC_STORAGE_SIZE 20 #define STM32_RTC_COMMON_HANDLER Vector48 #define STM32_RTC_COMMON_NUMBER 2 -#define STM32_RTC_ALARM_EXTI 18 -#define STM32_RTC_TAMP_STAMP_EXTI 19 -#define STM32_RTC_WKUP_EXTI 20 -#define STM32_RTC_IRQ_ENABLE() do { \ +#define STM32_RTC_EVENT_EXTI 19 +#define STM32_TAMP_EVENT_EXTI 21 +#define STM32_RTC_AND_TAMP_IRQ_ENABLE() do { \ nvicEnableVector(STM32_RTC_COMMON_NUMBER, \ - STM32_IRQ_EXTI19_21_IRQ_PRIORITY); \ + STM32_IRQ_EXTI1921_PRIORITY); \ } while (false) +/* Masks used to preserve state of reserved bits. */ +#define STM32_RTC_CR_MASK 0xE7FFFF7F +#define STM32_RTC_PRER_MASK 0x007F7FFF +#define STM32_TAMP_CR1_MASK 0x003C0003 +#define STM32_TAMP_CR2_MASK 0x030300FF +#define STM32_TAMP_FLTCR_MASK 0x000000FF +#define STM32_TAMP_IER_MASK 0x003C0003 + #if defined(STM32G081xx) || defined(__DOXYGEN__) #define STM32_HAS_RNG1 TRUE #define STM32_HAS_HASH1 FALSE diff --git a/os/hal/ports/STM32/STM32G4xx/platform.mk b/os/hal/ports/STM32/STM32G4xx/platform.mk index 1f5514269..9fb687fa6 100644 --- a/os/hal/ports/STM32/STM32G4xx/platform.mk +++ b/os/hal/ports/STM32/STM32G4xx/platform.mk @@ -31,7 +31,7 @@ include $(CHIBIOS)/os/hal/ports/STM32/LLD/DMAv1/driver.mk include $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1/driver.mk include $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv2/driver.mk include $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv2/driver.mk -#include $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv2/driver.mk +include $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv3/driver.mk include $(CHIBIOS)/os/hal/ports/STM32/LLD/QUADSPIv1/driver.mk include $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv2/driver.mk include $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/driver.mk diff --git a/readme.txt b/readme.txt index e536aa3cf..fe2339daf 100644 --- a/readme.txt +++ b/readme.txt @@ -74,6 +74,7 @@ ***************************************************************************** *** Next *** +- HAL: New RTCv3 driver for STM32G0xx and STM32G4xx. - HAL: Added support for DAC3 and DAC4 in STM32 DACv1 driver. - NIL: New functions: chSemResetWithMessageI() and chSemResetWithMessage(). - RT: New functions: chSemResetWithMessageI() and chSemResetWithMessage(). diff --git a/tools/ftl/processors/conf/mcuconf_stm32g071xx/mcuconf.h.ftl b/tools/ftl/processors/conf/mcuconf_stm32g071xx/mcuconf.h.ftl index b5c38c1c2..a1f695223 100644 --- a/tools/ftl/processors/conf/mcuconf_stm32g071xx/mcuconf.h.ftl +++ b/tools/ftl/processors/conf/mcuconf_stm32g071xx/mcuconf.h.ftl @@ -94,10 +94,11 @@ #define STM32_IRQ_EXTI0_1_PRIORITY ${doc.STM32_IRQ_EXTI0_1_PRIORITY!"3"} #define STM32_IRQ_EXTI2_3_PRIORITY ${doc.STM32_IRQ_EXTI2_3_PRIORITY!"3"} #define STM32_IRQ_EXTI4_15_PRIORITY ${doc.STM32_IRQ_EXTI4_15_PRIORITY!"3"} +#define STM32_IRQ_EXTI1921_PRIORITY ${doc.STM32_IRQ_EXTI1921_PRIORITY!"3"} #define STM32_IRQ_USART1_PRIORITY ${doc.STM32_IRQ_USART1_PRIORITY!"2"} #define STM32_IRQ_USART2_PRIORITY ${doc.STM32_IRQ_USART2_PRIORITY!"2"} -#define STM32_IRQ_USART3_4_LP1_PRIORITY ${doc.STM32_IRQ_USART3_4_LP1_PRIORITY!"1"} +#define STM32_IRQ_USART3_4_LP1_PRIORITY ${doc.STM32_IRQ_USART3_4_LP1_PRIORITY!"2"} #define STM32_IRQ_TIM1_UP_PRIORITY ${doc.STM32_IRQ_TIM1_UP_PRIORITY!"1"} #define STM32_IRQ_TIM1_CC_PRIORITY ${doc.STM32_IRQ_TIM1_CC_PRIORITY!"1"}