diff --git a/arch/arm/src/stm32f7/stm32_rtc.c b/arch/arm/src/stm32f7/stm32_rtc.c index 60ee8145dbe..12aa23f1c0b 100644 --- a/arch/arm/src/stm32f7/stm32_rtc.c +++ b/arch/arm/src/stm32f7/stm32_rtc.c @@ -1,9 +1,9 @@ /**************************************************************************** * arch/arm/src/stm32f7/stm32_rtc.c * - * Copyright (C) 2011, 2015-2018 Gregory Nutt. All rights reserved. + * Copyright (C) 2011, 2015-2019 Gregory Nutt. All rights reserved. * Author: Gregory Nutt - * David Sidrane + * David Sidrane * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -1081,23 +1081,6 @@ int up_rtc_initialize(void) return -ETIMEDOUT; } -#ifdef CONFIG_RTC_ALARM - /* Configure RTC interrupt to catch alarm interrupts. All RTC interrupts - * are connected to the EXTI controller. To enable the RTC Alarm - * interrupt, the following sequence is required: - * - * 1. Configure and enable the EXTI Line 17 RTC ALARM in interrupt mode - * and select the rising edge sensitivity. - * For STM32F7: - * EXTI line 21 RTC Tamper & Timestamp - * EXTI line 22 RTC Wakeup - * 2. Configure and enable the RTC_Alarm IRQ channel in the NVIC. - * 3. Configure the RTC to generate RTC alarms (Alarm A or Alarm B). - */ - - (void)stm32_exti_alarm(true, false, true, stm32_rtc_alarm_handler, NULL); -#endif - g_rtc_enabled = true; rtc_dumpregs("After Initialization"); return OK; @@ -1460,10 +1443,30 @@ int stm32_rtc_setalarm(FAR struct alm_setalarm_s *alminfo) FAR struct alm_cbinfo_s *cbinfo; rtc_alarmreg_t alarmreg; int ret = -EINVAL; + static bool once = false; DEBUGASSERT(alminfo != NULL); DEBUGASSERT(RTC_ALARM_LAST > alminfo->as_id); + /* Configure RTC interrupt to catch alarm interrupts. All RTC interrupts + * are connected to the EXTI controller. To enable the RTC Alarm + * interrupt, the following sequence is required: + * + * 1. Configure and enable the EXTI Line 17 RTC ALARM in interrupt mode + * and select the rising edge sensitivity. + * For STM32F7: + * EXTI line 21 RTC Tamper & Timestamp + * EXTI line 22 RTC Wakeup + * 2. Configure and enable the RTC_Alarm IRQ channel in the NVIC. + * 3. Configure the RTC to generate RTC alarms (Alarm A or Alarm B). + */ + + if (!once) + { + once = true; + (void)stm32_exti_alarm(true, false, true, stm32_rtc_alarm_handler, NULL); + } + /* REVISIT: Should test that the time is in the future */ rtc_dumptime(&alminfo->as_time, NULL, "New alarm time"); diff --git a/arch/arm/src/stm32h7/Kconfig b/arch/arm/src/stm32h7/Kconfig index b805596f60a..45dc258d987 100644 --- a/arch/arm/src/stm32h7/Kconfig +++ b/arch/arm/src/stm32h7/Kconfig @@ -134,6 +134,11 @@ config STM32H7_TIM bool default n +config STM32H7_RTC + bool "RTC" + default n + select RTC + config STM32H7_PWR bool "PWR" default n @@ -1002,6 +1007,82 @@ config STM32H7_SAVE_CRASHDUMP endif # STM32H7_BKPSRAM +config STM32H7_HAVE_RTC_SUBSECONDS + bool + select ARCH_HAVE_RTC_SUBSECONDS + default y + +menu "RTC Configuration" + depends on STM32H7_RTC + +config STM32H7_RTC_MAGIC_REG + int "BKP register" + default 0 + range 0 31 + ---help--- + The BKP register used to store/check the Magic value to determine if + RTC is already setup + +config STM32H7_RTC_MAGIC + hex "RTC Magic 1" + default 0xfacefeed + ---help--- + Value used as Magic to determine if the RTC is already setup + +config STM32H7_RTC_MAGIC_TIME_SET + hex "RTC Magic 2" + default 0xf00dface + ---help--- + Value used as Magic to determine if the RTC has been setup and has + time set + +choice + prompt "RTC clock source" + default STM32H7_RTC_LSECLOCK + +config STM32H7_RTC_HSECLOCK + bool "HSE clock" + ---help--- + Drive the RTC with the HSE clock, divided down to 1MHz. + +config STM32H7_RTC_LSECLOCK + bool "LSE clock" + ---help--- + Drive the RTC with the LSE clock + +config STM32H7_RTC_LSICLOCK + bool "LSI clock" + ---help--- + Drive the RTC with the LSI clock + +endchoice #"RTC clock source" + +if STM32H7_RTC_LSECLOCK + +config STM32H7_RTC_LSECLOCK_START_DRV_CAPABILITY + int "LSE oscillator drive capability level at LSE start-up" + default 0 + range 0 3 + ---help--- + 0 = Low drive capability (default) + 1 = Medium high drive capability + 2 = Medium low drive capability + 3 = High drive capability + +config STM32H7_RTC_LSECLOCK_RUN_DRV_CAPABILITY + int "LSE oscillator drive capability level after LSE start-up" + default 0 + range 0 3 + ---help--- + 0 = Low drive capability (default) + 1 = Medium high drive capability + 2 = Medium low drive capability + 3 = High drive capability + +endif # STM32H7_RTC_LSECLOCK + +endmenu # RTC Configuration + config STM32H7_CUSTOM_CLOCKCONFIG bool "Custom clock configuration" default n diff --git a/arch/arm/src/stm32h7/Make.defs b/arch/arm/src/stm32h7/Make.defs index 10d01a52344..0030c487a81 100644 --- a/arch/arm/src/stm32h7/Make.defs +++ b/arch/arm/src/stm32h7/Make.defs @@ -120,6 +120,14 @@ ifeq ($(CONFIG_STM32H7_DMA),y) CHIP_CSRCS += stm32_dma.c endif +ifeq ($(filter y,$(CONFIG_STM32H7_IWDG) $(CONFIG_STM32H7_RTC_LSICLOCK)),y) +CHIP_CSRCS += stm32_lsi.c +endif + +ifeq ($(CONFIG_STM32H7_RTC_LSECLOCK),y) +CHIP_CSRCS += stm32_lse.c +endif + ifeq ($(CONFIG_STM32H7_I2C),y) CHIP_CSRCS += stm32_i2c.c endif @@ -128,6 +136,19 @@ ifeq ($(CONFIG_STM32H7_PWR),y) CHIP_CSRCS += stm32_pwr.c endif +ifeq ($(CONFIG_STM32H7_RTC),y) +CHIP_CSRCS += stm32_rtc.c +ifeq ($(CONFIG_RTC_ALARM),y) +CHIP_CSRCS += stm32_exti_alarm.c +endif +ifeq ($(CONFIG_RTC_PERIODIC),y) +CHIP_CSRCS += stm32_exti_wakeup.c +endif +ifeq ($(CONFIG_RTC_DRIVER),y) +CHIP_CSRCS += stm32_rtc_lowerhalf.c +endif +endif + ifeq ($(CONFIG_STM32H7_SPI),y) CHIP_CSRCS += stm32_spi.c endif diff --git a/arch/arm/src/stm32h7/hardware/stm32_exti.h b/arch/arm/src/stm32h7/hardware/stm32_exti.h index e115c2b63dd..0667c9e9f83 100644 --- a/arch/arm/src/stm32h7/hardware/stm32_exti.h +++ b/arch/arm/src/stm32h7/hardware/stm32_exti.h @@ -160,6 +160,10 @@ #define EXIT_EVENT(n) STM32_EXTI_MASK(n) +#define EXTI_RTC_ALARM (1 << 17) /* EXTI line 17 = RTC Alarm event */ +#define EXTI_RTC_TAMPER (1 << 18) /* EXTI line 18 = RTC tamper, RTC timestamp, RCC LSECSS */ +#define EXTI_RTC_WAKEUP (1 << 19) /* EXTI line 19 = RTC wakeup timer */ + /* D3 pending clear selection register low 1-3. * D3 pending clear selection register high 1-3 * diff --git a/arch/arm/src/stm32h7/hardware/stm32_rtcc.h b/arch/arm/src/stm32h7/hardware/stm32_rtcc.h new file mode 100644 index 00000000000..9e4f0f0d160 --- /dev/null +++ b/arch/arm/src/stm32h7/hardware/stm32_rtcc.h @@ -0,0 +1,400 @@ +/************************************************************************************ + * arch/arm/src/stm32h7/hardware/stm32_rtcc.h + * + * Copyright (C) 2011-2016, 2019 Gregory Nutt. All rights reserved. + * Authors: Gregory Nutt + * David Sidrane + * + * 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 NuttX 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 OWNER 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 __ARCH_ARM_SRC_STM32H7_HARDWARE_STM32_RTCC_H +#define __ARCH_ARM_SRC_STM32H7_HARDWARE_STM32_RTCC_H + +/************************************************************************************ + * Pre-processor Definitions + ************************************************************************************/ + +/* Register Offsets *****************************************************************/ + +#define STM32_RTC_TR_OFFSET 0x0000 /* RTC time register */ +#define STM32_RTC_DR_OFFSET 0x0004 /* RTC date register */ +#define STM32_RTC_CR_OFFSET 0x0008 /* RTC control register */ +#define STM32_RTC_ISR_OFFSET 0x000c /* RTC initialization and status register */ +#define STM32_RTC_PRER_OFFSET 0x0010 /* RTC prescaler register */ +#define STM32_RTC_WUTR_OFFSET 0x0014 /* RTC wakeup timer register */ +#define STM32_RTC_ALRMAR_OFFSET 0x001c /* RTC alarm A register */ +#define STM32_RTC_ALRMBR_OFFSET 0x0020 /* RTC alarm B register */ +#define STM32_RTC_WPR_OFFSET 0x0024 /* RTC write protection register */ +#define STM32_RTC_SSR_OFFSET 0x0028 /* RTC sub second register */ +#define STM32_RTC_SHIFTR_OFFSET 0x002c /* RTC shift control register */ +#define STM32_RTC_TSTR_OFFSET 0x0030 /* RTC time stamp time register */ +#define STM32_RTC_TSDR_OFFSET 0x0034 /* RTC time stamp date register */ +#define STM32_RTC_TSSSR_OFFSET 0x0038 /* RTC timestamp sub second register */ +#define STM32_RTC_CALR_OFFSET 0x003c /* RTC calibration register */ +#define STM32_RTC_TAMPCR_OFFSET 0x0040 /* RTC tamper configuration register */ +#define STM32_RTC_ALRMASSR_OFFSET 0x0044 /* RTC alarm A sub second register */ +#define STM32_RTC_ALRMBSSR_OFFSET 0x0048 /* RTC alarm B sub second register */ +#define STM32_RTC_OR_OFFSET 0x004c /* RTC option register */ + +#define STM32_RTC_BKR_OFFSET(n) (0x0050+((n)<<2)) +#define STM32_RTC_BK0R_OFFSET 0x0050 /* RTC backup register 0 */ +#define STM32_RTC_BK1R_OFFSET 0x0054 /* RTC backup register 1 */ +#define STM32_RTC_BK2R_OFFSET 0x0058 /* RTC backup register 2 */ +#define STM32_RTC_BK3R_OFFSET 0x005c /* RTC backup register 3 */ +#define STM32_RTC_BK4R_OFFSET 0x0060 /* RTC backup register 4 */ +#define STM32_RTC_BK5R_OFFSET 0x0064 /* RTC backup register 5 */ +#define STM32_RTC_BK6R_OFFSET 0x0068 /* RTC backup register 6 */ +#define STM32_RTC_BK7R_OFFSET 0x006c /* RTC backup register 7 */ +#define STM32_RTC_BK8R_OFFSET 0x0070 /* RTC backup register 8 */ +#define STM32_RTC_BK9R_OFFSET 0x0074 /* RTC backup register 9 */ +#define STM32_RTC_BK10R_OFFSET 0x0078 /* RTC backup register 10 */ +#define STM32_RTC_BK11R_OFFSET 0x007c /* RTC backup register 11 */ +#define STM32_RTC_BK12R_OFFSET 0x0080 /* RTC backup register 12 */ +#define STM32_RTC_BK13R_OFFSET 0x0084 /* RTC backup register 13 */ +#define STM32_RTC_BK14R_OFFSET 0x0088 /* RTC backup register 14 */ +#define STM32_RTC_BK15R_OFFSET 0x008c /* RTC backup register 15 */ +#define STM32_RTC_BK16R_OFFSET 0x0090 /* RTC backup register 16 */ +#define STM32_RTC_BK17R_OFFSET 0x0094 /* RTC backup register 17 */ +#define STM32_RTC_BK18R_OFFSET 0x0098 /* RTC backup register 18 */ +#define STM32_RTC_BK19R_OFFSET 0x009c /* RTC backup register 19 */ +#define STM32_RTC_BK20R_OFFSET 0x00a0 /* RTC backup register 20 */ +#define STM32_RTC_BK21R_OFFSET 0x00a4 /* RTC backup register 21 */ +#define STM32_RTC_BK22R_OFFSET 0x00a8 /* RTC backup register 22 */ +#define STM32_RTC_BK23R_OFFSET 0x00ac /* RTC backup register 23 */ +#define STM32_RTC_BK24R_OFFSET 0x00b0 /* RTC backup register 24 */ +#define STM32_RTC_BK25R_OFFSET 0x00b4 /* RTC backup register 25 */ +#define STM32_RTC_BK26R_OFFSET 0x00b8 /* RTC backup register 26 */ +#define STM32_RTC_BK27R_OFFSET 0x00bc /* RTC backup register 27 */ +#define STM32_RTC_BK28R_OFFSET 0x00c0 /* RTC backup register 28 */ +#define STM32_RTC_BK29R_OFFSET 0x00c4 /* RTC backup register 29 */ +#define STM32_RTC_BK30R_OFFSET 0x00c8 /* RTC backup register 30 */ +#define STM32_RTC_BK31R_OFFSET 0x00cc /* RTC backup register 31 */ + +/* Register Addresses ***************************************************************/ + +#define STM32_RTC_TR (STM32_RTC_BASE+STM32_RTC_TR_OFFSET) +#define STM32_RTC_DR (STM32_RTC_BASE+STM32_RTC_DR_OFFSET) +#define STM32_RTC_CR (STM32_RTC_BASE+STM32_RTC_CR_OFFSET) +#define STM32_RTC_ISR (STM32_RTC_BASE+STM32_RTC_ISR_OFFSET) +#define STM32_RTC_PRER (STM32_RTC_BASE+STM32_RTC_PRER_OFFSET) +#define STM32_RTC_WUTR (STM32_RTC_BASE+STM32_RTC_WUTR_OFFSET) +#define STM32_RTC_ALRMAR (STM32_RTC_BASE+STM32_RTC_ALRMAR_OFFSET) +#define STM32_RTC_ALRMBR (STM32_RTC_BASE+STM32_RTC_ALRMBR_OFFSET) +#define STM32_RTC_WPR (STM32_RTC_BASE+STM32_RTC_WPR_OFFSET) +#define STM32_RTC_SSR (STM32_RTC_BASE+STM32_RTC_SSR_OFFSET) +#define STM32_RTC_SHIFTR (STM32_RTC_BASE+STM32_RTC_SHIFTR_OFFSET) +#define STM32_RTC_TSTR (STM32_RTC_BASE+STM32_RTC_TSTR_OFFSET) +#define STM32_RTC_TSDR (STM32_RTC_BASE+STM32_RTC_TSDR_OFFSET) +#define STM32_RTC_TSSSR (STM32_RTC_BASE+STM32_RTC_TSSSR_OFFSET) +#define STM32_RTC_CALR (STM32_RTC_BASE+STM32_RTC_CALR_OFFSET) +#define STM32_RTC_TAMPCR (STM32_RTC_BASE+STM32_RTC_TAMPCR_OFFSET) +#define STM32_RTC_ALRMASSR (STM32_RTC_BASE+STM32_RTC_ALRMASSR_OFFSET) +#define STM32_RTC_ALRMBSSR (STM32_RTC_BASE+STM32_RTC_ALRMBSSR_OFFSET) + +#define STM32_RTC_BKR(n) (STM32_RTC_BASE+STM32_RTC_BKR_OFFSET(n)) +#define STM32_RTC_BK0R (STM32_RTC_BASE+STM32_RTC_BK0R_OFFSET) +#define STM32_RTC_BK1R (STM32_RTC_BASE+STM32_RTC_BK1R_OFFSET) +#define STM32_RTC_BK2R (STM32_RTC_BASE+STM32_RTC_BK2R_OFFSET) +#define STM32_RTC_BK3R (STM32_RTC_BASE+STM32_RTC_BK3R_OFFSET) +#define STM32_RTC_BK4R (STM32_RTC_BASE+STM32_RTC_BK4R_OFFSET) +#define STM32_RTC_BK5R (STM32_RTC_BASE+STM32_RTC_BK5R_OFFSET) +#define STM32_RTC_BK6R (STM32_RTC_BASE+STM32_RTC_BK6R_OFFSET) +#define STM32_RTC_BK7R (STM32_RTC_BASE+STM32_RTC_BK7R_OFFSET) +#define STM32_RTC_BK8R (STM32_RTC_BASE+STM32_RTC_BK8R_OFFSET) +#define STM32_RTC_BK9R (STM32_RTC_BASE+STM32_RTC_BK9R_OFFSET) +#define STM32_RTC_BK10R (STM32_RTC_BASE+STM32_RTC_BK10R_OFFSET) +#define STM32_RTC_BK11R (STM32_RTC_BASE+STM32_RTC_BK11R_OFFSET) +#define STM32_RTC_BK12R (STM32_RTC_BASE+STM32_RTC_BK12R_OFFSET) +#define STM32_RTC_BK13R (STM32_RTC_BASE+STM32_RTC_BK13R_OFFSET) +#define STM32_RTC_BK14R (STM32_RTC_BASE+STM32_RTC_BK14R_OFFSET) +#define STM32_RTC_BK15R (STM32_RTC_BASE+STM32_RTC_BK15R_OFFSET) +#define STM32_RTC_BK16R (STM32_RTC_BASE+STM32_RTC_BK16R_OFFSET) +#define STM32_RTC_BK17R (STM32_RTC_BASE+STM32_RTC_BK17R_OFFSET) +#define STM32_RTC_BK18R (STM32_RTC_BASE+STM32_RTC_BK18R_OFFSET) +#define STM32_RTC_BK19R (STM32_RTC_BASE+STM32_RTC_BK19R_OFFSET) +#define STM32_RTC_BK20R (STM32_RTC_BASE+STM32_RTC_BK20R_OFFSET) +#define STM32_RTC_BK21R (STM32_RTC_BASE+STM32_RTC_BK21R_OFFSET) +#define STM32_RTC_BK22R (STM32_RTC_BASE+STM32_RTC_BK22R_OFFSET) +#define STM32_RTC_BK23R (STM32_RTC_BASE+STM32_RTC_BK23R_OFFSET) +#define STM32_RTC_BK24R (STM32_RTC_BASE+STM32_RTC_BK24R_OFFSET) +#define STM32_RTC_BK25R (STM32_RTC_BASE+STM32_RTC_BK25R_OFFSET) +#define STM32_RTC_BK26R (STM32_RTC_BASE+STM32_RTC_BK26R_OFFSET) +#define STM32_RTC_BK27R (STM32_RTC_BASE+STM32_RTC_BK27R_OFFSET) +#define STM32_RTC_BK28R (STM32_RTC_BASE+STM32_RTC_BK28R_OFFSET) +#define STM32_RTC_BK29R (STM32_RTC_BASE+STM32_RTC_BK29R_OFFSET) +#define STM32_RTC_BK30R (STM32_RTC_BASE+STM32_RTC_BK30R_OFFSET) +#define STM32_RTC_BK31R (STM32_RTC_BASE+STM32_RTC_BK31R_OFFSET) + +#define STM32_RTC_BKCOUNT 32 + +/* Register Bitfield Definitions ****************************************************/ + +/* RTC time register */ + +#define RTC_TR_SU_SHIFT (0) /* Bits 0-3: Second units in BCD format */ +#define RTC_TR_SU_MASK (15 << RTC_TR_SU_SHIFT) +#define RTC_TR_ST_SHIFT (4) /* Bits 4-6: Second tens in BCD format */ +#define RTC_TR_ST_MASK (7 << RTC_TR_ST_SHIFT) +#define RTC_TR_MNU_SHIFT (8) /* Bit 8-11: Minute units in BCD format */ +#define RTC_TR_MNU_MASK (15 << RTC_TR_MNU_SHIFT) +#define RTC_TR_MNT_SHIFT (12) /* Bits 12-14: Minute tens in BCD format */ +#define RTC_TR_MNT_MASK (7 << RTC_TR_MNT_SHIFT) +#define RTC_TR_HU_SHIFT (16) /* Bit 16-19: Hour units in BCD format */ +#define RTC_TR_HU_MASK (15 << RTC_TR_HU_SHIFT) +#define RTC_TR_HT_SHIFT (20) /* Bits 20-21: Hour tens in BCD format */ +#define RTC_TR_HT_MASK (3 << RTC_TR_HT_SHIFT) +#define RTC_TR_PM (1 << 22) /* Bit 22: AM/PM notation */ +#define RTC_TR_RESERVED_BITS (0xff808080) + +/* RTC date register */ + +#define RTC_DR_DU_SHIFT (0) /* Bits 0-3: Date units in BCD format */ +#define RTC_DR_DU_MASK (15 << RTC_DR_DU_SHIFT) +#define RTC_DR_DT_SHIFT (4) /* Bits 4-5: Date tens in BCD format */ +#define RTC_DR_DT_MASK (3 << RTC_DR_DT_SHIFT) +#define RTC_DR_MU_SHIFT (8) /* Bits 8-11: Month units in BCD format */ +#define RTC_DR_MU_MASK (15 << RTC_DR_MU_SHIFT) +#define RTC_DR_MT (1 << 12) /* Bit 12: Month tens in BCD format */ +#define RTC_DR_WDU_SHIFT (13) /* Bits 13-15: Week day units */ +#define RTC_DR_WDU_MASK (7 << RTC_DR_WDU_SHIFT) +# define RTC_DR_WDU_MONDAY (1 << RTC_DR_WDU_SHIFT) +# define RTC_DR_WDU_TUESDAY (2 << RTC_DR_WDU_SHIFT) +# define RTC_DR_WDU_WEDNESDAY (3 << RTC_DR_WDU_SHIFT) +# define RTC_DR_WDU_THURSDAY (4 << RTC_DR_WDU_SHIFT) +# define RTC_DR_WDU_FRIDAY (5 << RTC_DR_WDU_SHIFT) +# define RTC_DR_WDU_SATURDAY (6 << RTC_DR_WDU_SHIFT) +# define RTC_DR_WDU_SUNDAY (7 << RTC_DR_WDU_SHIFT) +#define RTC_DR_YU_SHIFT (16) /* Bits 16-19: Year units in BCD format */ +#define RTC_DR_YU_MASK (15 << RTC_DR_YU_SHIFT) +#define RTC_DR_YT_SHIFT (20) /* Bits 20-23: Year tens in BCD format */ +#define RTC_DR_YT_MASK (15 << RTC_DR_YT_SHIFT) +#define RTC_DR_RESERVED_BITS (0xff0000c0) + +/* RTC control register */ + +#define RTC_CR_WUCKSEL_SHIFT (0) /* Bits 0-2: Wakeup clock selection */ +#define RTC_CR_WUCKSEL_MASK (7 << RTC_CR_WUCKSEL_SHIFT) +# define RTC_CR_WUCKSEL_RTCDIV16 (0 << RTC_CR_WUCKSEL_SHIFT) /* 000: RTC/16 clock is selected */ +# define RTC_CR_WUCKSEL_RTCDIV8 (1 << RTC_CR_WUCKSEL_SHIFT) /* 001: RTC/8 clock is selected */ +# define RTC_CR_WUCKSEL_RTCDIV4 (2 << RTC_CR_WUCKSEL_SHIFT) /* 010: RTC/4 clock is selected */ +# define RTC_CR_WUCKSEL_RTCDIV2 (3 << RTC_CR_WUCKSEL_SHIFT) /* 011: RTC/2 clock is selected */ +# define RTC_CR_WUCKSEL_CKSPRE (4 << RTC_CR_WUCKSEL_SHIFT) /* 10x: ck_spre clock is selected */ +# define RTC_CR_WUCKSEL_CKSPREADD (6 << RTC_CR_WUCKSEL_SHIFT) /* 11x: ck_spr clock and 216 added WUT counter */ +#define RTC_CR_TSEDGE (1 << 3) /* Bit 3: Timestamp event active edge */ +#define RTC_CR_REFCKON (1 << 4) /* Bit 4: Reference clock detection enable (50 or 60 Hz) */ +#define RTC_CR_BYPSHAD (1 << 5) /* Bit 5: Bypass the shadow registers */ +#define RTC_CR_FMT (1 << 6) /* Bit 6: Hour format */ +#define RTC_CR_ALRAE (1 << 8) /* Bit 8: Alarm A enable */ +#define RTC_CR_ALRBE (1 << 9) /* Bit 9: Alarm B enable */ +#define RTC_CR_WUTE (1 << 10) /* Bit 10: Wakeup timer enable */ +#define RTC_CR_TSE (1 << 11) /* Bit 11: Time stamp enable */ +#define RTC_CR_ALRAIE (1 << 12) /* Bit 12: Alarm A interrupt enable */ +#define RTC_CR_ALRBIE (1 << 13) /* Bit 13: Alarm B interrupt enable */ +#define RTC_CR_WUTIE (1 << 14) /* Bit 14: Wakeup timer interrupt enable */ +#define RTC_CR_TSIE (1 << 15) /* Bit 15: Timestamp interrupt enable */ +#define RTC_CR_ADD1H (1 << 16) /* Bit 16: Add 1 hour (summer time change) */ +#define RTC_CR_SUB1H (1 << 17) /* Bit 17: Subtract 1 hour (winter time change) */ +#define RTC_CR_BKP (1 << 18) /* Bit 18: Backup */ +#define RTC_CR_COSEL (1 << 19) /* Bit 19: Calibration output selection */ +#define RTC_CR_POL (1 << 20) /* Bit 20: Output polarity */ +#define RTC_CR_OSEL_SHIFT (21) /* Bits 21-22: Output selection */ +#define RTC_CR_OSEL_MASK (3 << RTC_CR_OSEL_SHIFT) +# define RTC_CR_OSEL_DISABLED (0 << RTC_CR_OSEL_SHIFT) /* 00: Output disabled */ +# define RTC_CR_OSEL_ALRMA (1 << RTC_CR_OSEL_SHIFT) /* 01: Alarm A output enabled */ +# define RTC_CR_OSEL_ALRMB (2 << RTC_CR_OSEL_SHIFT) /* 10: Alarm B output enabled */ +# define RTC_CR_OSEL_WUT (3 << RTC_CR_OSEL_SHIFT) /* 11: Wakeup output enabled */ +#define RTC_CR_COE (1 << 23) /* Bit 23: Calibration output enable */ +#define RTC_CR_ITSE (1 << 24) /* Bit 24: Timestamp on internal event enable */ + +/* RTC initialization and status register */ + +#define RTC_ISR_ALRAWF (1 << 0) /* Bit 0: Alarm A write flag */ +#define RTC_ISR_ALRBWF (1 << 1) /* Bit 1: Alarm B write flag */ +#define RTC_ISR_WUTWF (1 << 2) /* Bit 2: Wakeup timer write flag */ +#define RTC_ISR_SHPF (1 << 3) /* Bit 3: Shift operation pending */ +#define RTC_ISR_INITS (1 << 4) /* Bit 4: Initialization status flag */ +#define RTC_ISR_RSF (1 << 5) /* Bit 5: Registers synchronization flag */ +#define RTC_ISR_INITF (1 << 6) /* Bit 6: Initialization flag */ +#define RTC_ISR_INIT (1 << 7) /* Bit 7: Initialization mode */ +#define RTC_ISR_ALRAF (1 << 8) /* Bit 8: Alarm A flag */ +#define RTC_ISR_ALRBF (1 << 9) /* Bit 9: Alarm B flag */ +#define RTC_ISR_WUTF (1 << 10) /* Bit 10: Wakeup timer flag */ +#define RTC_ISR_TSF (1 << 11) /* Bit 11: Timestamp flag */ +#define RTC_ISR_TSOVF (1 << 12) /* Bit 12: Timestamp overflow flag */ +#define RTC_ISR_TAMP1F (1 << 13) /* Bit 13: Tamper detection flag */ +#define RTC_ISR_TAMP2F (1 << 14) /* Bit 14: TAMPER2 detection flag */ +#define RTC_ISR_TAMP3F (1 << 15) /* Bit 15: TAMPER3 detection flag */ +#define RTC_ISR_RECALPF (1 << 16) /* Bit 16: Recalibration pending flag */ +#define RTC_ISR_ITSF (1 << 17) /* Bit 17: Internal time-stamp flag */ +#define RTC_ISR_ALLFLAGS (0x0003ffff) + +/* RTC prescaler register */ + +#define RTC_PRER_PREDIV_S_SHIFT (0) /* Bits 0-14: Synchronous prescaler factor */ +#define RTC_PRER_PREDIV_S_MASK (0x7fff << RTC_PRER_PREDIV_S_SHIFT) +#define RTC_PRER_PREDIV_A_SHIFT (16) /* Bits 16-22: Asynchronous prescaler factor */ +#define RTC_PRER_PREDIV_A_MASK (0x7f << RTC_PRER_PREDIV_A_SHIFT) + +/* RTC wakeup timer register */ + +#define RTC_WUTR_MASK (0xffff) /* Bits 15:0 Wakeup auto-reload value bits */ + +/* RTC alarm A/B registers */ + +#define RTC_ALRMR_SU_SHIFT (0) /* Bits 0-3: Second units in BCD format. */ +#define RTC_ALRMR_SU_MASK (15 << RTC_ALRMR_SU_SHIFT) +#define RTC_ALRMR_ST_SHIFT (4) /* Bits 4-6: Second tens in BCD format. */ +#define RTC_ALRMR_ST_MASK (7 << RTC_ALRMR_ST_SHIFT) +#define RTC_ALRMR_MSK1 (1 << 7) /* Bit 7 : Alarm A seconds mask */ +#define RTC_ALRMR_MNU_SHIFT (8) /* Bits 8-11: Minute units in BCD format. */ +#define RTC_ALRMR_MNU_MASK (15 << RTC_ALRMR_MNU_SHIFT) +#define RTC_ALRMR_MNT_SHIFT (12) /* Bits 12-14: Minute tens in BCD format. */ +#define RTC_ALRMR_MNT_MASK (7 << RTC_ALRMR_MNT_SHIFT) +#define RTC_ALRMR_MSK2 (1 << 15) /* Bit 15 : Alarm A minutes mask */ +#define RTC_ALRMR_HU_SHIFT (16) /* Bits 16-19: Hour units in BCD format. */ +#define RTC_ALRMR_HU_MASK (15 << RTC_ALRMR_HU_SHIFT) +#define RTC_ALRMR_HT_SHIFT (20) /* Bits 20-21: Hour tens in BCD format. */ +#define RTC_ALRMR_HT_MASK (3 << RTC_ALRMR_HT_SHIFT) +#define RTC_ALRMR_PM (1 << 22) /* Bit 22 : AM/PM notation */ +#define RTC_ALRMR_MSK3 (1 << 23) /* Bit 23 : Alarm A hours mask */ +#define RTC_ALRMR_DU_SHIFT (24) /* Bits 24-27: Date units or day in BCD format. */ +#define RTC_ALRMR_DU_MASK (15 << RTC_ALRMR_DU_SHIFT) +#define RTC_ALRMR_DT_SHIFT (28) /* Bits 28-29: Date tens in BCD format. */ +#define RTC_ALRMR_DT_MASK (3 << RTC_ALRMR_DT_SHIFT) +#define RTC_ALRMR_WDSEL (1 << 30) /* Bit 30: Week day selection */ +#define RTC_ALRMR_MSK4 (1 << 31) /* Bit 31: Alarm A date mask */ + +/* RTC write protection register */ + +#define RTC_WPR_MASK (0xff) /* Bits 0-7: Write protection key */ + +/* RTC sub second register */ + +#define RTC_SSR_MASK (0xffff) /* Bits 0-15: Sub second value */ + +/* RTC shift control register */ + +#define RTC_SHIFTR_SUBFS_SHIFT (0) /* Bits 0-14: Subtract a fraction of a second */ +#define RTC_SHIFTR_SUBFS_MASK (0x7fff << RTC_SHIFTR_SUBFS_SHIFT) +#define RTC_SHIFTR_ADD1S (1 << 31) /* Bit 31: Add one second */ + +/* RTC time stamp time register */ + +#define RTC_TSTR_SU_SHIFT (0) /* Bits 0-3: Second units in BCD format. */ +#define RTC_TSTR_SU_MASK (15 << RTC_TSTR_SU_SHIFT) +#define RTC_TSTR_ST_SHIFT (4) /* Bits 4-6: Second tens in BCD format. */ +#define RTC_TSTR_ST_MASK (7 << RTC_TSTR_ST_SHIFT) +#define RTC_TSTR_MNU_SHIFT (8) /* Bits 8-11: Minute units in BCD format. */ +#define RTC_TSTR_MNU_MASK (15 << RTC_TSTR_MNU_SHIFT) +#define RTC_TSTR_MNT_SHIFT (12) /* Bits 12-14: Minute tens in BCD format. */ +#define RTC_TSTR_MNT_MASK (7 << RTC_TSTR_MNT_SHIFT) +#define RTC_TSTR_HU_SHIFT (16) /* Bits 16-19: Hour units in BCD format. */ +#define RTC_TSTR_HU_MASK (15 << RTC_TSTR_HU_SHIFT) +#define RTC_TSTR_HT_SHIFT (20) /* Bits 20-21: Hour tens in BCD format. */ +#define RTC_TSTR_HT_MASK (3 << RTC_TSTR_HT_SHIFT) +#define RTC_TSTR_PM (1 << 22) /* Bit 22: AM/PM notation */ + +/* RTC time stamp date register */ + +#define RTC_TSDR_DU_SHIFT (0) /* Bit 0-3: Date units in BCD format */ +#define RTC_TSDR_DU_MASK (15 << RTC_TSDR_DU_SHIFT) +#define RTC_TSDR_DT_SHIFT (4) /* Bits 4-5: Date tens in BCD format */ +#define RTC_TSDR_DT_MASK (3 << RTC_TSDR_DT_SHIFT) +#define RTC_TSDR_MU_SHIFT (8) /* Bits 8-11: Month units in BCD format */ +#define RTC_TSDR_MU_MASK (15 << RTC_TSDR_MU_SHIFT) +#define RTC_TSDR_MT (1 << 12) /* Bit 12: Month tens in BCD format */ +#define RTC_TSDR_WDU_SHIFT (13) /* Bits 13-15: Week day units */ +#define RTC_TSDR_WDU_MASK (7 << RTC_TSDR_WDU_SHIFT) + +/* RTC timestamp sub second register */ + +#define RTC_TSSSR_MASK (0xffff) /* Bits 0-15: Sub second value */ + +/* RTC calibration register */ + +#define RTC_CALR_CALM_SHIFT (0) /* Bits 0-8: Calibration minus */ +#define RTC_CALR_CALM_MASK (0x1ff << RTC_CALR_CALM_SHIFT) +#define RTC_CALR_CALW16 (1 << 13) /* Bit 13: Use a 16-second calibration cycle period */ +#define RTC_CALR_CALW8 (1 << 14) /* Bit 14: Use an 8-second calibration cycle period */ +#define RTC_CALR_CALP (1 << 15) /* Bit 15: Increase frequency of RTC by 488.5 ppm */ + +/* RTC tamper configuration register */ + +#define RTC_TAMPCR_TAMP1E (1 << 0) /* Bit 0: RTC_TAMP1 input detection enable */ +#define RTC_TAMPCR_TAMP1TRG (1 << 1) /* Bit 1: Active level for RTC_TAMP1 input */ +#define RTC_TAMPCR_TAMPIE (1 << 2) /* Bit 2: Tamper interrupt enable */ +#define RTC_TAMPCR_TAMP2E (1 << 3) /* Bit 3: RTC_TAMP2 input detection enable */ +#define RTC_TAMPCR_TAMP2TRG (1 << 4) /* Bit 4: Active level for RTC_TAMP2 input */ +#define RTC_TAMPCR_TAMP3E (1 << 5) /* Bit 5: RTC_TAMP3 detection enable */ +#define RTC_TAMPCR_TAMP3TRG (1 << 6) /* Bit 6: Active level for RTC_TAMP3 input */ +#define RTC_TAMPCR_TAMPTS (1 << 7) /* Bit 7: Activate timestamp on tamper detection event */ +#define RTC_TAMPCR_TAMPFREQ_SHIFT (8) /* Bits 8-10: Tamper sampling frequency */ +#define RTC_TAMPCR_TAMPFREQ_MASK (7 << RTC_TAMPCR_TAMPFREQ_SHIFT) +# define RTC_TAMPCR_TAMPFREQ_DIV32768 (0 << RTC_TAMPCR_TAMPFREQ_SHIFT) /* RTCCLK / 32768 (1 Hz) */ +# define RTC_TAMPCR_TAMPFREQ_DIV16384 (1 << RTC_TAMPCR_TAMPFREQ_SHIFT) /* RTCCLK / 16384 (2 Hz) */ +# define RTC_TAMPCR_TAMPFREQ_DIV8192 (2 << RTC_TAMPCR_TAMPFREQ_SHIFT) /* RTCCLK / 8192 (4 Hz) */ +# define RTC_TAMPCR_TAMPFREQ_DIV4096 (3 << RTC_TAMPCR_TAMPFREQ_SHIFT) /* RTCCLK / 4096 (8 Hz) */ +# define RTC_TAMPCR_TAMPFREQ_DIV2048 (4 << RTC_TAMPCR_TAMPFREQ_SHIFT) /* RTCCLK / 2048 (16 Hz) */ +# define RTC_TAMPCR_TAMPFREQ_DIV1024 (5 << RTC_TAMPCR_TAMPFREQ_SHIFT) /* RTCCLK / 1024 (32 Hz) */ +# define RTC_TAMPCR_TAMPFREQ_DIV512 (6 << RTC_TAMPCR_TAMPFREQ_SHIFT) /* RTCCLK / 512 (64 Hz) */ +# define RTC_TAMPCR_TAMPFREQ_DIV256 (7 << RTC_TAMPCR_TAMPFREQ_SHIFT) /* RTCCLK / 256 (128 Hz) */ +#define RTC_TAMPCR_TAMPFLT_SHIFT (11) /* Bits 11-12: RTC_TAMPx filter count */ +#define RTC_TAMPCR_TAMPFLT_MASK (3 << RTC_TAMPCR_TAMPFLT_SHIFT) +#define RTC_TAMPCR_TAMPPRCH_SHIFT (13) /* Bits 13-14: RTC_TAMPx precharge duration */ +#define RTC_TAMPCR_TAMPPRCH_MASK (3 << RTC_TAMPCR_TAMPPRCH_SHIFT) +# define RTC_TAMPCR_TAMPPRCH_1CYCLE (0 << RTC_TAMPCR_TAMPPRCH_SHIFT) /* 1 RTCCLK cycle */ +# define RTC_TAMPCR_TAMPPRCH_2CYCLES (1 << RTC_TAMPCR_TAMPPRCH_SHIFT) /* 2 RTCCLK cycles */ +# define RTC_TAMPCR_TAMPPRCH_4CYCLES (2 << RTC_TAMPCR_TAMPPRCH_SHIFT) /* 4 RTCCLK cycles */ +# define RTC_TAMPCR_TAMPPRCH_5CYCLES (3 << RTC_TAMPCR_TAMPPRCH_SHIFT) /* 8 RTCCLK cycles */ +#define RTC_TAMPCR_TAMPPUDIS (1 << 15) /* Bit 15: RTC_TAMPx pull-up disable */ +#define RTC_TAMPCR_TAMP1IE (1 << 16) /* Bit 16: Tamper 1 interrupt enable */ +#define RTC_TAMPCR_TAMP1NOERASE (1 << 17) /* Bit 17: Tamper 1 no erase */ +#define RTC_TAMPCR_TAMP1MF (1 << 18) /* Bit 18: Tamper 1 mask flag */ +#define RTC_TAMPCR_TAMP2IE (1 << 19) /* Bit 19: Tamper 2 interrupt enable */ +#define RTC_TAMPCR_TAMP2NOERASE (1 << 20) /* Bit 20: Tamper 2 no erase */ +#define RTC_TAMPCR_TAMP2MF (1 << 21) /* Bit 21: Tamper 2 mask flag */ +#define RTC_TAMPCR_TAMP3IE (1 << 22) /* Bit 22: Tamper 3 interrupt enable */ +#define RTC_TAMPCR_TAMP3NOERASE (1 << 23) /* Bit 23: Tamper 3 no erase */ +#define RTC_TAMPCR_TAMP3MF (1 << 24) /* Bit 24: Tamper 3 mask flag */ + +/* RTC alarm A/B sub second register */ + +#define RTC_ALRMSSR_SS_SHIFT (0) /* Bits 0-14: Sub second value */ +#define RTC_ALRMSSR_SS_MASK (0x7fff << RTC_ALRMSSR_SS_SHIFT) +#define RTC_ALRMSSR_MASKSS_SHIFT (24) /* Bits 24-27: Mask the most-significant bits starting at this bit */ +#define RTC_ALRMSSR_MASKSS_MASK (0xf << RTC_ALRMSSR_MASKSS_SHIFT) + +/* RTC option register */ + +#define RTC_OR_RTC_ALARM_TYPE (1 << 0) /* Bit 0: RTC_ALARM output type on PC13 */ +#define RTC_OR_RTC_OUT_RMP (1 << 1) /* Bit 1: RTC_OUT remap */ + + +#endif /* __ARCH_ARM_SRC_STM32H7_HARDWARE_STM32_RTCC_H */ diff --git a/arch/arm/src/stm32h7/hardware/stm32h7x3xx_rcc.h b/arch/arm/src/stm32h7/hardware/stm32h7x3xx_rcc.h index 6e16c218200..6fea50fce98 100644 --- a/arch/arm/src/stm32h7/hardware/stm32h7x3xx_rcc.h +++ b/arch/arm/src/stm32h7/hardware/stm32h7x3xx_rcc.h @@ -1111,13 +1111,24 @@ #define RCC_BDCR_LSEON (1 << 0) /* Bit 0: External Low Speed oscillator enable */ #define RCC_BDCR_LSERDY (1 << 1) /* Bit 1: External Low Speed oscillator Ready */ #define RCC_BDCR_LSEBYP (1 << 2) /* Bit 2: External Low Speed oscillator Bypass */ +#define RCC_BDCR_LSEDRV_SHIFT (3) /* Bits 4:3: LSE oscillator Drive selection */ +#define RCC_BDCR_LSEDRV_MASK (3 << RCC_BDCR_LSEDRV_SHIFT) +# define RCC_BDCR_LSEDRV_LOW (0 << RCC_BDCR_LSEDRV_SHIFT) /* 00: Low driving capability */ +# define RCC_BDCR_LSEDRV_MEDHI (1 << RCC_BDCR_LSEDRV_SHIFT) /* 01: Medium high driving capability */ +# define RCC_BDCR_LSEDRV_MEDLO (2 << RCC_BDCR_LSEDRV_SHIFT) /* 10: Medium low driving capability */ +# define RCC_BDCR_LSEDRV_HIGH (3 << RCC_BDCR_LSEDRV_SHIFT) /* 11: High driving capability */ +#define RCC_BDCR_LSECSSON (1 << 5) /* Bit 5: LSE clock security system enable */ +#define RCC_BDCR_LSECSSD (1 << 6) /* Bit 6: LSE clock security system failure detection */ + /* Bit 7: Reserved */ #define RCC_BDCR_RTCSEL_SHIFT (8) /* Bits 9:8: RTC clock source selection */ #define RCC_BDCR_RTCSEL_MASK (3 << RCC_BDCR_RTCSEL_SHIFT) # define RCC_BDCR_RTCSEL_NOCLK (0 << RCC_BDCR_RTCSEL_SHIFT) /* 00: No clock */ # define RCC_BDCR_RTCSEL_LSE (1 << RCC_BDCR_RTCSEL_SHIFT) /* 01: LSE oscillator clock used as RTC clock */ # define RCC_BDCR_RTCSEL_LSI (2 << RCC_BDCR_RTCSEL_SHIFT) /* 10: LSI oscillator clock used as RTC clock */ # define RCC_BDCR_RTCSEL_HSE (3 << RCC_BDCR_RTCSEL_SHIFT) /* 11: HSE oscillator clock divided by 128 used as RTC clock */ + /* Bits 10-15: Reserved */ #define RCC_BDCR_RTCEN (1 << 15) /* Bit 15: RTC clock enable */ #define RCC_BDCR_BDRST (1 << 16) /* Bit 16: Backup domain software reset */ + /* Bits 17-31: Reserved */ #endif /* __ARCH_ARM_SRC_STM32H7_HARDWARE_STM32H7X3XX_RCC_H */ diff --git a/arch/arm/src/stm32h7/stm32_alarm.h b/arch/arm/src/stm32h7/stm32_alarm.h new file mode 100644 index 00000000000..4efc3f56d41 --- /dev/null +++ b/arch/arm/src/stm32h7/stm32_alarm.h @@ -0,0 +1,175 @@ +/**************************************************************************** + * arch/arm/src/include/stm32f7/stm32_alarm.h + * + * Copyright (C) 2016, 2018, 2019 Gregory Nutt. All rights reserved. + * Authors: Neil Hancock - delegated to Gregory Nutt Mar 30, 2016 + * David Sidrane + * + * 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 NuttX 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 OWNER 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 __ARCH_ARM_SRC_STM32H7_STM32_ALARM_H +#define __ARCH_ARM_SRC_STM32H7_STM32_ALARM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +typedef CODE void (*alm_callback_t)(FAR void *arg, unsigned int alarmid); + +/* These features map to STM32 RTC from stm32H7xx */ + +enum alm_id_e +{ + RTC_ALARMA = 0, /* RTC ALARM A */ + RTC_ALARMB, /* RTC ALARM B */ + RTC_ALARM_LAST +}; + +/* Structure used to pass parameters to set an alarm */ + +struct alm_setalarm_s +{ + int as_id; /* enum alm_id_e */ + struct tm as_time; /* Alarm expiration time */ + alm_callback_t as_cb; /* Callback (if non-NULL) */ + FAR void *as_arg; /* Argument for callback */ +}; + +/* Structure used to pass parameters to query an alarm */ + +struct alm_rdalarm_s +{ + int ar_id; /* enum alm_id_e */ + FAR struct rtc_time *ar_time; /* Argument for storing ALARM RTC time */ +}; +#endif + +#ifdef CONFIG_RTC_PERIODIC +typedef CODE int (*wakeupcb_t)(void); +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +/**************************************************************************** + * Name: stm32_rtc_setalarm + * + * Description: + * Set an alarm to an absolute time using associated hardware. + * + * Input Parameters: + * alminfo - Information about the alarm configuration. + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +int stm32_rtc_setalarm(FAR struct alm_setalarm_s *alminfo); + +/**************************************************************************** + * Name: stm32_rtc_rdalarm + * + * Description: + * Query an alarm configured in hardware. + * + * Input Parameters: + * alminfo - Information about the alarm configuration. + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +int stm32_rtc_rdalarm(FAR struct alm_rdalarm_s *alminfo); + +/**************************************************************************** + * Name: stm32_rtc_cancelalarm + * + * Description: + * Cancel an alarm. + * + * Input Parameters: + * alarmid - Identifies the alarm to be cancelled + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +int stm32_rtc_cancelalarm(enum alm_id_e alarmid); +#endif /* CONFIG_RTC_ALARM */ + +#ifdef CONFIG_RTC_PERIODIC +/**************************************************************************** + * Name: stm32_rtc_setperiodic + * + * Description: + * Set a periodic RTC wakeup + * + * Input Parameters: + * period - Time to sleep between wakeups + * callback - Function to call when the period expires. + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +int stm32_rtc_setperiodic(FAR const struct timespec *period, + wakeupcb_t callback); + +/**************************************************************************** + * Name: stm32_rtc_cancelperiodic + * + * Description: + * Cancel a periodic wakeup + * + * Input Parameters: + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +int stm32_rtc_cancelperiodic(void); +#endif /* CONFIG_RTC_PERIODIC */ + +#endif /* __ARCH_ARM_SRC_STM32H7_STM32_ALARM_H */ diff --git a/arch/arm/src/stm32h7/stm32_exti_alarm.c b/arch/arm/src/stm32h7/stm32_exti_alarm.c new file mode 100644 index 00000000000..41d113e58de --- /dev/null +++ b/arch/arm/src/stm32h7/stm32_exti_alarm.c @@ -0,0 +1,163 @@ +/**************************************************************************** + * arch/arm/src/stm32h7/stm32_exti_alarm.c + * + * Copyright (C) 2015, 2017, 2019 Gregory Nutt. All rights reserved. + * Authors: Gregory Nutt + * David Sidrane + * + * This file derives from similar logic for the STM32 F1: + * + * Copyright (C) 2009, 2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * Diego Sanchez + * + * 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 NuttX 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 OWNER 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include +#include +#include + +#include + +#include "up_arch.h" +#include "stm32_gpio.h" +#include "stm32_exti.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Interrupt handlers attached to the ALARM EXTI */ + +static xcpt_t g_alarm_callback; +static void *g_callback_arg; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_exti_alarm_isr + * + * Description: + * EXTI ALARM interrupt service routine/dispatcher + * + ****************************************************************************/ + +static int stm32_exti_alarm_isr(int irq, void *context, FAR void *arg) +{ + int ret = OK; + + /* Clear the pending EXTI interrupt */ + + putreg32(EXTI_RTC_ALARM, STM32_EXTI_CPUPR1); + + /* And dispatch the interrupt to the handler */ + + if (g_alarm_callback != NULL) + { + ret = g_alarm_callback(irq, context, g_callback_arg); + } + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_exti_alarm + * + * Description: + * Sets/clears EXTI alarm interrupt. + * + * Input Parameters: + * - rising/falling edge: enables interrupt on rising/falling edget + * - event: generate event when set + * - func: when non-NULL, generate interrupt + * - arg: Argument passed to the interrupt callback + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure indicating the + * nature of the failure. + * + ****************************************************************************/ + +int stm32_exti_alarm(bool risingedge, bool fallingedge, bool event, + xcpt_t func, void *arg) +{ + g_alarm_callback = func; + g_callback_arg = arg; + + /* Install external interrupt handlers (if not already attached) */ + + if (func) + { + irq_attach(STM32_IRQ_RTCALARM, stm32_exti_alarm_isr, NULL); + up_enable_irq(STM32_IRQ_RTCALARM); + } + else + { + up_disable_irq(STM32_IRQ_RTCALARM); + } + + /* Configure rising/falling edges */ + + modifyreg32(STM32_EXTI_RTSR1, + risingedge ? 0 : EXTI_RTC_ALARM, + risingedge ? EXTI_RTC_ALARM : 0); + modifyreg32(STM32_EXTI_FTSR1, + fallingedge ? 0 : EXTI_RTC_ALARM, + fallingedge ? EXTI_RTC_ALARM : 0); + + /* Enable Events and Interrupts */ + + modifyreg32(STM32_EXTI_CPUEMR1, + event ? 0 : EXTI_RTC_ALARM, + event ? EXTI_RTC_ALARM : 0); + modifyreg32(STM32_EXTI_CPUIMR1, + func ? 0 : EXTI_RTC_ALARM, + func ? EXTI_RTC_ALARM : 0); + + return OK; +} diff --git a/arch/arm/src/stm32h7/stm32_exti_wakeup.c b/arch/arm/src/stm32h7/stm32_exti_wakeup.c new file mode 100644 index 00000000000..50f11aeb041 --- /dev/null +++ b/arch/arm/src/stm32h7/stm32_exti_wakeup.c @@ -0,0 +1,154 @@ +/**************************************************************************** + * arch/arm/src/stm32h7/stm32_exti_wakeup.c + * + * Copyright (C) 2009, 2012, 2017-2018 Gregory Nutt. All rights reserved. + * Authors: Gregory Nutt + * Juha Niskanen + * David Sidrane + * + * 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 NuttX 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 OWNER 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include +#include +#include + +#include + +#include "up_arch.h" +#include "chip.h" +#include "stm32_gpio.h" +#include "stm32_exti.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Interrupt handlers attached to the RTC WAKEUP EXTI */ + +static xcpt_t g_wakeup_callback; +static void *g_callback_arg; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_exti_wakeup_isr + * + * Description: + * EXTI periodic WAKEUP interrupt service routine/dispatcher + * + ****************************************************************************/ + +static int stm32_exti_wakeup_isr(int irq, void *context, FAR void *arg) +{ + int ret = OK; + + /* Dispatch the interrupt to the handler */ + + if (g_wakeup_callback != NULL) + { + ret = g_wakeup_callback(irq, context, g_callback_arg); + } + + /* Clear the pending EXTI interrupt */ + + putreg32(EXTI_RTC_WAKEUP, STM32_EXTI_CPUPR1); + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_exti_wakeup + * + * Description: + * Sets/clears EXTI wakeup interrupt. + * + * Input Parameters: + * - rising/falling edge: enables interrupt on rising/falling edges + * - event: generate event when set + * - func: when non-NULL, generate interrupt + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure indicating the + * nature of the failure. + * + ****************************************************************************/ + +int stm32_exti_wakeup(bool risingedge, bool fallingedge, bool event, + xcpt_t func, void *arg) +{ + g_wakeup_callback = func; + g_callback_arg = arg; + + /* Install external interrupt handlers (if not already attached) */ + + if (func) + { + irq_attach(STM32_IRQ_RTCWKUP, stm32_exti_wakeup_isr, NULL); + up_enable_irq(STM32_IRQ_RTCWKUP); + } + else + { + up_disable_irq(STM32_IRQ_RTCWKUP); + } + + /* Configure rising/falling edges */ + + modifyreg32(STM32_EXTI_RTSR1, + risingedge ? 0 : EXTI_RTC_WAKEUP, + risingedge ? EXTI_RTC_WAKEUP : 0); + modifyreg32(STM32_EXTI_FTSR1, + fallingedge ? 0 : EXTI_RTC_WAKEUP, + fallingedge ? EXTI_RTC_WAKEUP : 0); + + /* Enable Events and Interrupts */ + + modifyreg32(STM32_EXTI_CPUEMR1, + event ? 0 : EXTI_RTC_WAKEUP, + event ? EXTI_RTC_WAKEUP : 0); + modifyreg32(STM32_EXTI_CPUIMR1, + func ? 0 : EXTI_RTC_WAKEUP, + func ? EXTI_RTC_WAKEUP : 0); + + return OK; +} diff --git a/arch/arm/src/stm32h7/stm32_lse.c b/arch/arm/src/stm32h7/stm32_lse.c new file mode 100644 index 00000000000..0fd15c94436 --- /dev/null +++ b/arch/arm/src/stm32h7/stm32_lse.c @@ -0,0 +1,131 @@ +/**************************************************************************** + * arch/arm/src/stm32h7/stm32_lse.c + * + * Copyright (C) 2017, 2019 Gregory Nutt. All rights reserved. + * Authors: Gregory Nutt + * David Sidrane + * + * 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 NuttX 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 OWNER 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "up_arch.h" + +#include "stm32_rcc.h" +#include "stm32_pwr.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_STM32H7_RTC_LSECLOCK_START_DRV_CAPABILITY +# if CONFIG_STM32H7_RTC_LSECLOCK_START_DRV_CAPABILITY < 0 || \ + CONFIG_STM32H7_RTC_LSECLOCK_START_DRV_CAPABILITY > 3 +# error "Invalid LSE drive capability setting" +#endif +#endif + +#ifdef CONFIG_STM32H7_RTC_LSECLOCK_RUN_DRV_CAPABILITY +# if CONFIG_STM32H7_RTC_LSECLOCK_RUN_DRV_CAPABILITY < 0 || \ + CONFIG_STM32H7_RTC_LSECLOCK_RUN_DRV_CAPABILITY > 3 +# error "Invalid LSE drive capability setting" +#endif +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_rcc_enablelse + * + * Description: + * Enable the External Low-Speed (LSE) oscillator. + * + ****************************************************************************/ + +void stm32_rcc_enablelse(void) +{ + uint32_t regval; + + /* Check if the External Low-Speed (LSE) oscillator is already running. */ + + regval = getreg32(STM32_RCC_BDCR); + + if ((regval & (RCC_BDCR_LSEON | RCC_BDCR_LSERDY)) != + (RCC_BDCR_LSEON | RCC_BDCR_LSERDY)) + { + /* The LSE is in the RTC domain and write access is denied to this + * domain after reset, you have to enable write access using DBP bit + * in the PWR CR register before to configuring the LSE. + */ + + stm32_pwr_enablebkp(true); + + /* Enable the External Low-Speed (LSE) oscillator by setting the + * LSEON bit the RCC BDCR register. + */ + + regval |= RCC_BDCR_LSEON; + +#ifdef CONFIG_STM32H7_RTC_LSECLOCK_START_DRV_CAPABILITY + /* Set start-up drive capability for LSE oscillator. */ + + regval &= ~RCC_BDCR_LSEDRV_MASK; + regval |= CONFIG_STM32H7_RTC_LSECLOCK_START_DRV_CAPABILITY << + RCC_BDCR_LSEDRV_SHIFT; +#endif + + putreg32(regval, STM32_RCC_BDCR); + + /* Wait for the LSE clock to be ready */ + + while (((regval = getreg32(STM32_RCC_BDCR)) & RCC_BDCR_LSERDY) == 0); + +#if defined(CONFIG_STM32H7_RTC_LSECLOCK_RUN_DRV_CAPABILITY) && \ + CONFIG_STM32H7_RTC_LSECLOCK_START_DRV_CAPABILITY != \ + CONFIG_STM32H7_RTC_LSECLOCK_RUN_DRV_CAPABILITY + /* Set running drive capability for LSE oscillator. */ + + regval &= ~RCC_BDCR_LSEDRV_MASK; + regval |= CONFIG_STM32H7_RTC_LSECLOCK_RUN_DRV_CAPABILITY << + RCC_BDCR_LSEDRV_SHIFT; + putreg32(regval, STM32_RCC_BDCR); +#endif + + /* Disable backup domain access if it was disabled on entry */ + + stm32_pwr_enablebkp(false); + } +} diff --git a/arch/arm/src/stm32h7/stm32_lsi.c b/arch/arm/src/stm32h7/stm32_lsi.c new file mode 100644 index 00000000000..28a3068a0f2 --- /dev/null +++ b/arch/arm/src/stm32h7/stm32_lsi.c @@ -0,0 +1,89 @@ +/**************************************************************************** + * arch/arm/src/stm32h7/stm32_lsi.c + * + * Copyright (C) 2012, 2015-2016, 2019 Gregory Nutt. All rights reserved. + * Authors: Gregory Nutt + * David Sidrane + * + * 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 NuttX 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 OWNER 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "up_arch.h" + +#include "stm32_rcc.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_rcc_enablelsi + * + * Description: + * Enable the Internal Low-Speed (LSI) RC Oscillator. + * + ****************************************************************************/ + +void stm32_rcc_enablelsi(void) +{ + /* Enable the Internal Low-Speed (LSI) RC Oscillator by setting the LSION + * bit the RCC CSR register. + */ + + modifyreg32(STM32_RCC_CSR, 0, RCC_CSR_LSION); + + /* Wait for the internal RC 40 kHz oscillator to be stable. */ + + while ((getreg32(STM32_RCC_CSR) & RCC_CSR_LSIRDY) == 0); +} + +/**************************************************************************** + * Name: stm32_rcc_disablelsi + * + * Description: + * Disable the Internal Low-Speed (LSI) RC Oscillator. + * + ****************************************************************************/ + +void stm32_rcc_disablelsi(void) +{ + /* Enable the Internal Low-Speed (LSI) RC Oscillator by setting the LSION + * bit the RCC CSR register. + */ + + modifyreg32(STM32_RCC_CSR, RCC_CSR_LSION, 0); + + /* LSIRDY should go low after 3 LSI clock cycles */ +} diff --git a/arch/arm/src/stm32h7/stm32_rtc.c b/arch/arm/src/stm32h7/stm32_rtc.c new file mode 100644 index 00000000000..0c356c4ca46 --- /dev/null +++ b/arch/arm/src/stm32h7/stm32_rtc.c @@ -0,0 +1,1960 @@ +/**************************************************************************** + * arch/arm/src/stm32h7/stm32_rtc.c + * + * Copyright (C) 2011, 2015-2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * David Sidrane + * + * 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 NuttX 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 OWNER 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "up_arch.h" + +#include "stm32_rcc.h" +#include "stm32_pwr.h" +#include "stm32_exti.h" +#include "stm32_rtc.h" + +#include + +#ifdef CONFIG_STM32H7_RTC + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* Configuration ************************************************************/ +/* This RTC implementation supports + * - date/time RTC hardware + * - extended functions Alarm A and B + * */ + +#ifndef CONFIG_RTC_DATETIME +# error "CONFIG_RTC_DATETIME must be set to use this driver" +#endif + +#ifdef CONFIG_RTC_HIRES +# error "CONFIG_RTC_HIRES must NOT be set with this driver" +#endif + +#ifndef CONFIG_STM32H7_PWR +# error "CONFIG_STM32H7_PWR must selected to use this driver" +#endif + +/* Constants ****************************************************************/ + +#if defined(CONFIG_STM32H7_RTC_HSECLOCK) +# define RCC_BDCR_RTCSEL RCC_BDCR_RTCSEL_HSE +#elif defined(CONFIG_STM32H7_RTC_LSICLOCK) +# define RCC_BDCR_RTCSEL RCC_BDCR_RTCSEL_LSI +#elif defined(CONFIG_STM32H7_RTC_LSECLOCK) +# define RCC_BDCR_RTCSEL RCC_BDCR_RTCSEL_LSE +#else +# warning "RCC_BDCR_RTCSEL_NOCLK has been selected - RTC will not count" +#endif + +#define SYNCHRO_TIMEOUT (0x00020000) +#define INITMODE_TIMEOUT (0x00010000) + +/* Time conversions */ + +#define MINUTES_IN_HOUR 60 +#define HOURS_IN_DAY 24 + +#define hours_add(parm_hrs) \ + time->tm_hour += parm_hrs;\ + if ((HOURS_IN_DAY-1) < (time->tm_hour))\ + {\ + time->tm_hour = (parm_hrs - HOURS_IN_DAY);\ + } + +#define RTC_ALRMR_DIS_MASK (RTC_ALRMR_MSK4 | RTC_ALRMR_MSK3 | \ + RTC_ALRMR_MSK2 | RTC_ALRMR_MSK1) +#define RTC_ALRMR_DIS_DATE_MASK (RTC_ALRMR_MSK4) +#define RTC_ALRMR_ENABLE (0) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +typedef unsigned int rtc_alarmreg_t; + +struct alm_cbinfo_s +{ + volatile alm_callback_t ac_cb; /* Client callback function */ + volatile FAR void *ac_arg; /* Argument to pass with the callback function */ +}; +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +/* Callback to use when an EXTI is activated */ + +static struct alm_cbinfo_s g_alarmcb[RTC_ALARM_LAST]; +#endif + +#ifdef CONFIG_RTC_PERIODIC +static wakeupcb_t g_wakeupcb; +static bool g_wakeup_enabled; /* True: Wakeup interrupts are enabled */ +#endif + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* g_rtc_enabled is set true after the RTC has successfully initialized */ + +volatile bool g_rtc_enabled = false; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int rtchw_check_alrawf(void); +static int rtchw_set_alrmar(rtc_alarmreg_t alarmreg); +#if CONFIG_RTC_NALARMS > 1 +static int rtchw_check_alrbwf(void); +static int rtchw_set_alrmbr(rtc_alarmreg_t alarmreg); +#endif +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: rtc_dumpregs + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_RTC_INFO +static void rtc_dumpregs(FAR const char *msg) +{ + int rtc_state; + + rtcinfo("%s:\n", msg); + rtcinfo(" TR: %08x\n", getreg32(STM32_RTC_TR)); + rtcinfo(" DR: %08x\n", getreg32(STM32_RTC_DR)); + rtcinfo(" CR: %08x\n", getreg32(STM32_RTC_CR)); + rtcinfo(" ISR: %08x\n", getreg32(STM32_RTC_ISR)); + rtcinfo(" PRER: %08x\n", getreg32(STM32_RTC_PRER)); + rtcinfo(" WUTR: %08x\n", getreg32(STM32_RTC_WUTR)); + rtcinfo(" ALRMAR: %08x\n", getreg32(STM32_RTC_ALRMAR)); + rtcinfo(" ALRMBR: %08x\n", getreg32(STM32_RTC_ALRMBR)); + rtcinfo(" SHIFTR: %08x\n", getreg32(STM32_RTC_SHIFTR)); + rtcinfo(" TSTR: %08x\n", getreg32(STM32_RTC_TSTR)); + rtcinfo(" TSDR: %08x\n", getreg32(STM32_RTC_TSDR)); + rtcinfo(" TSSSR: %08x\n", getreg32(STM32_RTC_TSSSR)); + rtcinfo(" CALR: %08x\n", getreg32(STM32_RTC_CALR)); + rtcinfo(" TAMPCR: %08x\n", getreg32(STM32_RTC_TAMPCR)); + rtcinfo("ALRMASSR: %08x\n", getreg32(STM32_RTC_ALRMASSR)); + rtcinfo("ALRMBSSR: %08x\n", getreg32(STM32_RTC_ALRMBSSR)); + rtcinfo("MAGICREG: %08x\n", getreg32(RTC_MAGIC_REG)); + + rtc_state = + ((getreg32(STM32_EXTI_RTSR1) & EXTI_RTC_ALARM) ? 0x1000 : 0) | + ((getreg32(STM32_EXTI_FTSR1) & EXTI_RTC_ALARM) ? 0x0100 : 0) | + ((getreg32(STM32_EXTI_CPUIMR1) & EXTI_RTC_ALARM) ? 0x0010 : 0) | + ((getreg32(STM32_EXTI_CPUEMR1) & EXTI_RTC_ALARM) ? 0x0001 : 0); + rtcinfo("EXTI (RTSR1 FTSR1 ISR EVT): %01x\n",rtc_state); +} +#else +# define rtc_dumpregs(msg) +#endif + +/**************************************************************************** + * Name: rtc_dumptime + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_RTC_INFO +static void rtc_dumptime(FAR const struct tm *tp, FAR const uint32_t *usecs, + FAR const char *msg) +{ + rtcinfo("%s:\n", msg); + rtcinfo(" tm_sec: %08x\n", tp->tm_sec); + rtcinfo(" tm_min: %08x\n", tp->tm_min); + rtcinfo(" tm_hour: %08x\n", tp->tm_hour); + rtcinfo(" tm_mday: %08x\n", tp->tm_mday); + rtcinfo(" tm_mon: %08x\n", tp->tm_mon); + rtcinfo(" tm_year: %08x\n", tp->tm_year); + + if (usecs != NULL) + { + rtcinfo(" usecs: %08x\n", (unsigned int)*usecs); + } +} +#else +# define rtc_dumptime(tp, usecs, msg) +#endif + +/**************************************************************************** + * Name: rtc_wprunlock + * + * Description: + * Disable RTC write protection + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void rtc_wprunlock(void) +{ + /* Enable write access to the backup domain (RTC registers, RTC backup data + * registers and backup SRAM). + */ + + stm32_pwr_enablebkp(true); + + /* The following steps are required to unlock the write protection on all + * the RTC registers (except for RTC_ISR[13:8], RTC_TAFCR, and RTC_BKPxR). + * + * 1. Write 0xCA into the RTC_WPR register. + * 2. Write 0x53 into the RTC_WPR register. + * + * Writing a wrong key re-activates the write protection. + */ + + putreg32(0xca, STM32_RTC_WPR); + putreg32(0x53, STM32_RTC_WPR); +} + +/**************************************************************************** + * Name: rtc_wprlock + * + * Description: + * Enable RTC write protection + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void rtc_wprlock(void) +{ + /* Writing any wrong key re-activates the write protection. */ + + putreg32(0xff, STM32_RTC_WPR); + + /* Disable write access to the backup domain (RTC registers, RTC backup + * data registers and backup SRAM). + */ + + stm32_pwr_enablebkp(false); +} + +/**************************************************************************** + * Name: rtc_synchwait + * + * Description: + * Waits until the RTC Time and Date registers (RTC_TR and RTC_DR) are + * synchronized with RTC APB clock. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +static int rtc_synchwait(void) +{ + volatile uint32_t timeout; + uint32_t regval; + int ret; + + /* Disable the write protection for RTC registers */ + + rtc_wprunlock(); + + /* Clear Registers synchronization flag (RSF) */ + + regval = getreg32(STM32_RTC_ISR); + regval &= ~RTC_ISR_RSF; + putreg32(regval, STM32_RTC_ISR); + + /* Now wait the registers to become synchronised */ + + ret = -ETIMEDOUT; + for (timeout = 0; timeout < SYNCHRO_TIMEOUT; timeout++) + { + regval = getreg32(STM32_RTC_ISR); + if ((regval & RTC_ISR_RSF) != 0) + { + /* Synchronized */ + + ret = OK; + break; + } + } + + /* Re-enable the write protection for RTC registers */ + + rtc_wprlock(); + return ret; +} + +/**************************************************************************** + * Name: rtc_enterinit + * + * Description: + * Enter RTC initialization mode. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +static int rtc_enterinit(void) +{ + volatile uint32_t timeout; + uint32_t regval; + int ret; + + /* Check if the Initialization mode is already set */ + + regval = getreg32(STM32_RTC_ISR); + + ret = OK; + if ((regval & RTC_ISR_INITF) == 0) + { + /* Set the Initialization mode */ + + putreg32(RTC_ISR_INIT, STM32_RTC_ISR); + + /* Wait until the RTC is in the INIT state (or a timeout occurs) */ + + ret = -ETIMEDOUT; + for (timeout = 0; timeout < INITMODE_TIMEOUT; timeout++) + { + regval = getreg32(STM32_RTC_ISR); + if ((regval & RTC_ISR_INITF) != 0) + { + ret = OK; + break; + } + } + } + + return ret; +} + +/**************************************************************************** + * Name: rtc_exitinit + * + * Description: + * Exit RTC initialization mode. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +static void rtc_exitinit(void) +{ + uint32_t regval; + + regval = getreg32(STM32_RTC_ISR); + regval &= ~(RTC_ISR_INIT); + putreg32(regval, STM32_RTC_ISR); +} + +/**************************************************************************** + * Name: rtc_bin2bcd + * + * Description: + * Converts a 2 digit binary to BCD format + * + * Input Parameters: + * value - The byte to be converted. + * + * Returned Value: + * The value in BCD representation + * + ****************************************************************************/ + +static uint32_t rtc_bin2bcd(int value) +{ + uint32_t msbcd = 0; + + while (value >= 10) + { + msbcd++; + value -= 10; + } + + return (msbcd << 4) | value; +} + +/**************************************************************************** + * Name: rtc_bin2bcd + * + * Description: + * Convert from 2 digit BCD to binary. + * + * Input Parameters: + * value - The BCD value to be converted. + * + * Returned Value: + * The value in binary representation + * + ****************************************************************************/ + +static int rtc_bcd2bin(uint32_t value) +{ + uint32_t tens = (value >> 4) * 10; + return (int)(tens + (value & 0x0f)); +} + +/**************************************************************************** + * Name: rtc_setup + * + * Description: + * Performs first time configuration of the RTC. A special value written + * into back-up register 0 will prevent this function from being called on + * sub-sequent resets or power up. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +static int rtc_setup(void) +{ + uint32_t regval; + int ret; + + /* Disable the write protection for RTC registers */ + + rtc_wprunlock(); + + /* Set Initialization mode */ + + ret = rtc_enterinit(); + if (ret == OK) + { + /* Set the 24 hour format by clearing the FMT bit in the RTC + * control register + */ + + regval = getreg32(STM32_RTC_CR); + regval &= ~RTC_CR_FMT; + putreg32(regval, STM32_RTC_CR); + + /* Configure RTC pre-scaler with the required values */ + +#ifdef CONFIG_STM32H7_RTC_HSECLOCK + /* For a 1 MHz clock this yields 0.9999360041 Hz on the second + * timer - which is pretty close. + */ + + putreg32(((uint32_t)7182 << RTC_PRER_PREDIV_S_SHIFT) | + ((uint32_t)0x7f << RTC_PRER_PREDIV_A_SHIFT), + STM32_RTC_PRER); +#else + /* Correct values for 32.768 KHz LSE clock and inaccurate LSI clock */ + + putreg32(((uint32_t)0xff << RTC_PRER_PREDIV_S_SHIFT) | + ((uint32_t)0x7f << RTC_PRER_PREDIV_A_SHIFT), + STM32_RTC_PRER); +#endif + + /* Exit RTC initialization mode */ + + rtc_exitinit(); + } + + /* Re-enable the write protection for RTC registers */ + + rtc_wprlock(); + + return ret; +} + +/**************************************************************************** + * Name: rtc_resume + * + * Description: + * Called when the RTC was already initialized on a previous power cycle. + * This just brings the RTC back into full operation. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +static void rtc_resume(void) +{ +#ifdef CONFIG_RTC_ALARM + uint32_t regval; + + /* Clear the RTC alarm flags */ + + regval = getreg32(STM32_RTC_ISR); + regval &= ~(RTC_ISR_ALRAF | RTC_ISR_ALRBF); + putreg32(regval, STM32_RTC_ISR); + + /* Clear the RTC Alarm Pending bit */ + + putreg32(EXTI_RTC_ALARM, STM32_EXTI_CPUPR1); +#endif +} + +/**************************************************************************** + * Name: stm32_rtc_alarm_handler + * + * Description: + * RTC ALARM interrupt service routine through the EXTI line + * + * Input Parameters: + * irq - The IRQ number that generated the interrupt + * context - Architecture specific register save information. + * + * Returned Value: + * Zero (OK) on success; A negated errno value on failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int stm32_rtc_alarm_handler(int irq, void *context, void *arg) +{ + FAR struct alm_cbinfo_s *cbinfo; + alm_callback_t cb; + FAR void *cbarg; + uint32_t isr; + uint32_t cr; + int ret = OK; + + /* Enable write access to the backup domain (RTC registers, RTC + * backup data registers and backup SRAM). + */ + + (void)stm32_pwr_enablebkp(true); + + isr = getreg32(STM32_RTC_ISR); + + /* Check for EXTI from Alarm A or B and handle according */ + + if ((isr & RTC_ISR_ALRAF) != 0) + { + cr = getreg32(STM32_RTC_CR); + if ((cr & RTC_CR_ALRAIE) != 0) + { + cbinfo = &g_alarmcb[RTC_ALARMA]; + if (cbinfo->ac_cb != NULL) + { + /* Alarm A callback */ + + cb = cbinfo->ac_cb; + cbarg = (FAR void *)cbinfo->ac_arg; + + cbinfo->ac_cb = NULL; + cbinfo->ac_arg = NULL; + + cb(cbarg, RTC_ALARMA); + } + + isr = getreg32(STM32_RTC_ISR); + isr &= ~RTC_ISR_ALRAF; + putreg32(isr, STM32_RTC_ISR); + } + } + +#if CONFIG_RTC_NALARMS > 1 + if ((isr & RTC_ISR_ALRBF) != 0) + { + cr = getreg32(STM32_RTC_CR); + if ((cr & RTC_CR_ALRBIE) != 0) + { + cbinfo = &g_alarmcb[RTC_ALARMB]; + if (cbinfo->ac_cb != NULL) + { + /* Alarm B callback */ + + cb = cbinfo->ac_cb; + cbarg = (FAR void *)cbinfo->ac_arg; + + cbinfo->ac_cb = NULL; + cbinfo->ac_arg = NULL; + + cb(cbarg, RTC_ALARMB); + } + + isr = getreg32(STM32_RTC_ISR); + isr &= ~RTC_ISR_ALRBF; + putreg32(isr, STM32_RTC_ISR); + } + } +#endif + + /* Disable write access to the backup domain (RTC registers, RTC backup + * data registers and backup SRAM). + */ + + (void)stm32_pwr_enablebkp(false); + + return ret; +} +#endif + +/**************************************************************************** + * Name: rtchw_check_alrXwf X= a or B + * + * Description: + * Check registers + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int rtchw_check_alrawf(void) +{ + volatile uint32_t timeout; + uint32_t regval; + int ret = -ETIMEDOUT; + + /* Check RTC_ISR ALRAWF for access to alarm register, + * Can take 2 RTCCLK cycles or timeout + * CubeMX use GetTick. + */ + + for (timeout = 0; timeout < INITMODE_TIMEOUT; timeout++) + { + regval = getreg32(STM32_RTC_ISR); + if ((regval & RTC_ISR_ALRAWF) != 0) + { + ret = OK; + break; + } + } + + return ret; +} +#endif + +#if defined(CONFIG_RTC_ALARM) && CONFIG_RTC_NALARMS > 1 +static int rtchw_check_alrbwf(void) +{ + volatile uint32_t timeout; + uint32_t regval; + int ret = -ETIMEDOUT; + + /* Check RTC_ISR ALRBWF for access to alarm register, + * can take 2 RTCCLK cycles or timeout + * CubeMX use GetTick. + */ + + for (timeout = 0; timeout < INITMODE_TIMEOUT; timeout++) + { + regval = getreg32(STM32_RTC_ISR); + if ((regval & RTC_ISR_ALRBWF) != 0) + { + ret = OK; + break; + } + } + + return ret; +} +#endif + +/**************************************************************************** + * Name: stm32_rtchw_set_alrmXr X is a or b + * + * Description: + * Set the alarm (A or B) hardware registers, using the required hardware + * access protocol + * + * Input Parameters: + * alarmreg - the register + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int rtchw_set_alrmar(rtc_alarmreg_t alarmreg) +{ + int isr; + int ret = -EBUSY; + + /* Disable the write protection for RTC registers */ + + rtc_wprunlock(); + + /* Disable RTC alarm A & Interrupt A */ + + modifyreg32(STM32_RTC_CR, (RTC_CR_ALRAE | RTC_CR_ALRAIE), 0); + + /* Ensure Alarm A flag reset; this is edge triggered */ + + isr = getreg32(STM32_RTC_ISR) & ~RTC_ISR_ALRAF; + putreg32(isr, STM32_RTC_ISR); + + /* Wait for Alarm A to be writable */ + + ret = rtchw_check_alrawf(); + if (ret != OK) + { + goto errout_with_wprunlock; + } + + /* Set the RTC Alarm A register */ + + putreg32(alarmreg, STM32_RTC_ALRMAR); + putreg32(0, STM32_RTC_ALRMASSR); + rtcinfo(" ALRMAR: %08x\n", getreg32(STM32_RTC_ALRMAR)); + + /* Enable RTC alarm A */ + + modifyreg32(STM32_RTC_CR, 0, (RTC_CR_ALRAE | RTC_CR_ALRAIE)); + +errout_with_wprunlock: + rtc_wprlock(); + return ret; +} +#endif + +#if defined(CONFIG_RTC_ALARM) && CONFIG_RTC_NALARMS > 1 +static int rtchw_set_alrmbr(rtc_alarmreg_t alarmreg) +{ + int isr; + int ret = -EBUSY; + + /* Disable the write protection for RTC registers */ + + rtc_wprunlock(); + + /* Disable RTC alarm B & Interrupt B */ + + modifyreg32(STM32_RTC_CR, (RTC_CR_ALRBE | RTC_CR_ALRBIE), 0); + + /* Ensure Alarm B flag reset; this is edge triggered */ + + isr = getreg32(STM32_RTC_ISR) & ~RTC_ISR_ALRBF; + putreg32(isr, STM32_RTC_ISR); + + /* Wait for Alarm B to be writable */ + + ret = rtchw_check_alrbwf(); + if (ret != OK) + { + goto rtchw_set_alrmbr_exit; + } + + /* Set the RTC Alarm B register */ + + putreg32(alarmreg, STM32_RTC_ALRMBR); + putreg32(0, STM32_RTC_ALRMBSSR); + rtcinfo(" ALRMBR: %08x\n", getreg32(STM32_RTC_ALRMBR)); + + /* Enable RTC alarm B */ + + modifyreg32(STM32_RTC_CR, 0, (RTC_CR_ALRBE | RTC_CR_ALRBIE)); + +rtchw_set_alrmbr_exit: + rtc_wprlock(); + return ret; +} +#endif + +/**************************************************************************** + * Name: stm32_rtc_getalarmdatetime + * + * Description: + * Get the current date and time for a RTC alarm. + * + * Input Parameters: + * reg - RTC alarm register + * tp - The location to return the high resolution time value. + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int stm32_rtc_getalarmdatetime(rtc_alarmreg_t reg, FAR struct tm *tp) +{ + uint32_t data, tmp; + + DEBUGASSERT(tp != NULL); + + /* Sample the data time register. */ + + data = getreg32(reg); + + /* Convert the RTC time to fields in struct tm format. All of the STM32 + * ranges of values correspond between struct tm and the time register. + */ + + tmp = (data & (RTC_ALRMR_SU_MASK | RTC_ALRMR_ST_MASK)) >> RTC_ALRMR_SU_SHIFT; + tp->tm_sec = rtc_bcd2bin(tmp); + + tmp = (data & (RTC_ALRMR_MNU_MASK | RTC_ALRMR_MNT_MASK)) >> RTC_ALRMR_MNU_SHIFT; + tp->tm_min = rtc_bcd2bin(tmp); + + tmp = (data & (RTC_ALRMR_HU_MASK | RTC_ALRMR_HT_MASK)) >> RTC_ALRMR_HU_SHIFT; + tp->tm_hour = rtc_bcd2bin(tmp); + + tmp = (data & (RTC_ALRMR_DU_MASK | RTC_ALRMR_DT_MASK)) >> RTC_ALRMR_DU_SHIFT; + tp->tm_mday = rtc_bcd2bin(tmp); + + return OK; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_rtc_initialize + * + * Description: + * Initialize the hardware RTC per the selected configuration. This + * function is called once during the OS initialization sequence + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +int up_rtc_initialize(void) +{ + uint32_t regval; + uint32_t tr_bkp; + uint32_t dr_bkp; + int ret; + int maxretry = 10; + int nretry = 0; + + /* Clocking for the PWR block must be provided. However, this is done + * unconditionally in stm32h7xxx_rcc.c on power up. This done + * unconditionally because the PWR block is also needed to set the + * internal voltage regulator for maximum performance. + */ + + /* Select the clock source */ + /* Save the token before losing it when resetting */ + + regval = getreg32(RTC_MAGIC_REG); + + /* Enable write access to the backup domain (RTC registers, RTC + * backup data registers and backup SRAM). + */ + + stm32_pwr_enablebkp(true); + + if (regval != RTC_MAGIC && regval != RTC_MAGIC_TIME_SET) + { + /* Issue the Backup domain Reset Per Section 5.3.20 DocID028270 Rev 2 + * The LSEON, LSEBYP, RTCSEL and RTCEN bits in the RCC backup domain + * control register (RCC_BDCR) are in the Backup domain. As a result, + * after Reset, these bits are write-protected and the DBP bit in the + * PWR power control register (PWR_CR1) has to be set before these can + * be modified. Refer to Section 5.1.1: System reset on page 148 for + * further information. These bits are only reset after a Backup + * domain Reset (see Section 5.1.3: Backup domain reset). + * + * This has to be done here so that PWR is already enabled + */ + + modifyreg32(STM32_RCC_BDCR, 0, RCC_BDCR_BDRST); + modifyreg32(STM32_RCC_BDCR, RCC_BDCR_BDRST, 0); + +#if RCC_BDCR_RTCSEL == RCC_BDCR_RTCSEL_LSE + /* Because of the Backup domain Reset - we must re enable the LSE */ + + stm32_rcc_enablelse(); +#endif + + /* Some boards do not have the external 32khz oscillator installed, for + * those boards we must fallback to the crummy internal RC clock or the + * external high rate clock + */ + +#ifdef CONFIG_STM32H7_RTC_HSECLOCK + /* Use the HSE clock as the input to the RTC block */ + + rtc_dumpregs("On reset HSE"); + +#elif defined(CONFIG_STM32H7_RTC_LSICLOCK) + /* Use the LSI clock as the input to the RTC block */ + + rtc_dumpregs("On reset LSI"); + +#elif defined(CONFIG_STM32H7_RTC_LSECLOCK) + /* Use the LSE clock as the input to the RTC block */ + + rtc_dumpregs("On reset LSE"); + +#endif + modifyreg32(STM32_RCC_BDCR, RCC_BDCR_RTCSEL_MASK, RCC_BDCR_RTCSEL); + + /* Enable the RTC Clock by setting the RTCEN bit in the RCC register */ + + modifyreg32(STM32_RCC_BDCR, 0, RCC_BDCR_RTCEN); + } + else + { + uint32_t clksrc = getreg32(STM32_RCC_BDCR); + + rtc_dumpregs("On reset warm"); + + /* The RTC is already in use: check if the clock source has changed */ + + if ((clksrc & RCC_BDCR_RTCSEL_MASK) != RCC_BDCR_RTCSEL) + { + tr_bkp = getreg32(STM32_RTC_TR); + dr_bkp = getreg32(STM32_RTC_DR); + modifyreg32(STM32_RCC_BDCR, 0, RCC_BDCR_BDRST); + modifyreg32(STM32_RCC_BDCR, RCC_BDCR_BDRST, 0); + +# if RCC_BDCR_RTCSEL == RCC_BDCR_RTCSEL_LSE + /* Because of the Backup domain Reset - we must re enable the LSE + * if it is used + */ + + stm32_rcc_enablelse(); +#endif + /* Change to the new clock as the input to the RTC block */ + + modifyreg32(STM32_RCC_BDCR, RCC_BDCR_RTCSEL_MASK, RCC_BDCR_RTCSEL); + + putreg32(tr_bkp, STM32_RTC_TR); + putreg32(dr_bkp, STM32_RTC_DR); + + /* Keep the fact that the RTC is initialized */ + + putreg32(RTC_MAGIC, RTC_MAGIC_REG); + + /* Enable the RTC Clock by setting the RTCEN bit in the RCC + * register. + */ + + modifyreg32(STM32_RCC_BDCR, 0, RCC_BDCR_RTCEN); + } + } + + /* Loop, attempting to initialize/resume the RTC. This loop is necessary + * because it seems that occasionally it takes longer to initialize the + * RTC (the actual failure is in rtc_synchwait()). + */ + + do + { + /* Wait for the RTC Time and Date registers to be synchronized with + * RTC APB clock. + */ + + ret = rtc_synchwait(); + + /* Check that rtc_syncwait() returned successfully */ + + switch (ret) + { + case OK: + { + rtcinfo("rtc_syncwait() okay\n"); + break; + } + + default: + { + rtcerr("ERROR: rtc_syncwait() failed (%d)\n", ret); + break; + } + } + } + while (ret != OK && ++nretry < maxretry); + + /* Check if the one-time initialization of the RTC has already been + * performed. We can determine this by checking if the magic number + * has been writing to to back-up date register DR0. + */ + + if (regval != RTC_MAGIC && regval != RTC_MAGIC_TIME_SET) + { + rtcinfo("Do setup\n"); + + /* Perform the one-time setup of the LSE clocking to the RTC */ + + ret = rtc_setup(); + + /* Remember that the RTC is initialized */ + + putreg32(RTC_MAGIC, RTC_MAGIC_REG); + } + else + { + rtcinfo("Do resume\n"); + + /* RTC already set-up, just resume normal operation */ + + rtc_resume(); + rtc_dumpregs("Did resume"); + } + + /* Disable write access to the backup domain (RTC registers, RTC backup + * data registers and backup SRAM). + */ + + stm32_pwr_enablebkp(false); + + if (ret != OK && nretry > 0) + { + rtcinfo("setup/resume ran %d times and failed with %d\n", + nretry, ret); + return -ETIMEDOUT; + } + + g_rtc_enabled = true; + rtc_dumpregs("After Initialization"); + return OK; +} + +/**************************************************************************** + * Name: stm32_rtc_getdatetime_with_subseconds + * + * Description: + * Get the current date and time from the date/time RTC. This interface + * is only supported by the date/time RTC hardware implementation. + * It is used to replace the system timer. It is only used by the RTOS + * during initialization to set up the system time when CONFIG_RTC and + * CONFIG_RTC_DATETIME are selected (and CONFIG_RTC_HIRES is not). + * + * NOTE: Some date/time RTC hardware is capability of sub-second accuracy. + * That sub-second accuracy is returned through 'nsec'. + * + * Input Parameters: + * tp - The location to return the high resolution time value. + * nsec - The location to return the subsecond time value. + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_STM32H7_HAVE_RTC_SUBSECONDS +int stm32_rtc_getdatetime_with_subseconds(FAR struct tm *tp, FAR long *nsec) +#else +int up_rtc_getdatetime(FAR struct tm *tp) +#endif +{ + uint32_t dr; + uint32_t tr; + uint32_t tmp; +#ifdef CONFIG_STM32H7_HAVE_RTC_SUBSECONDS + uint32_t ssr; + uint32_t prediv_s; + uint32_t usecs; +#endif + + /* Sample the data time registers. There is a race condition here... If + * we sample the time just before midnight on December 31, the date could + * be wrong because the day rolled over while were sampling. Thus loop for + * checking overflow here is needed. There is a race condition with + * subseconds too. If we sample TR register just before second rolling + * and subseconds are read at wrong second, we get wrong time. + */ + + do + { + dr = getreg32(STM32_RTC_DR); + tr = getreg32(STM32_RTC_TR); +#ifdef CONFIG_STM32H7_HAVE_RTC_SUBSECONDS + ssr = getreg32(STM32_RTC_SSR); + tmp = getreg32(STM32_RTC_TR); + if (tmp != tr) + { + continue; + } +#endif + tmp = getreg32(STM32_RTC_DR); + if (tmp == dr) + { + break; + } + } + while (1); + + rtc_dumpregs("Reading Time"); + + /* Convert the RTC time to fields in struct tm format. All of the STM32 + * ranges of values correspond between struct tm and the time register. + */ + + tmp = (tr & (RTC_TR_SU_MASK | RTC_TR_ST_MASK)) >> RTC_TR_SU_SHIFT; + tp->tm_sec = rtc_bcd2bin(tmp); + + tmp = (tr & (RTC_TR_MNU_MASK | RTC_TR_MNT_MASK)) >> RTC_TR_MNU_SHIFT; + tp->tm_min = rtc_bcd2bin(tmp); + + tmp = (tr & (RTC_TR_HU_MASK | RTC_TR_HT_MASK)) >> RTC_TR_HU_SHIFT; + tp->tm_hour = rtc_bcd2bin(tmp); + + /* Now convert the RTC date to fields in struct tm format: + * Days: 1-31 match in both cases. + * Month: STM32 is 1-12, struct tm is 0-11. + * Years: STM32 is 00-99, struct tm is years since 1900. + * WeekDay: STM32 is 1 = Mon - 7 = Sun + * + * Issue: I am not sure what the STM32 years mean. Are these the + * years 2000-2099? I'll assume so. + */ + + tmp = (dr & (RTC_DR_DU_MASK | RTC_DR_DT_MASK)) >> RTC_DR_DU_SHIFT; + tp->tm_mday = rtc_bcd2bin(tmp); + + tmp = (dr & (RTC_DR_MU_MASK | RTC_DR_MT)) >> RTC_DR_MU_SHIFT; + tp->tm_mon = rtc_bcd2bin(tmp) - 1; + + tmp = (dr & (RTC_DR_YU_MASK | RTC_DR_YT_MASK)) >> RTC_DR_YU_SHIFT; + tp->tm_year = rtc_bcd2bin(tmp) + 100; + +#if defined(CONFIG_LIBC_LOCALTIME) || defined(CONFIG_TIME_EXTENDED) + tmp = (dr & RTC_DR_WDU_MASK) >> RTC_DR_WDU_SHIFT; + tp->tm_wday = tmp % 7; + tp->tm_yday = tp->tm_mday + + clock_daysbeforemonth(tp->tm_mon, clock_isleapyear(tp->tm_year + 1900)); + tp->tm_isdst = 0; +#endif + +#ifdef CONFIG_STM32H7_HAVE_RTC_SUBSECONDS + /* Return RTC sub-seconds if a non-NULL value + * of nsec has been provided to receive the sub-second value. + */ + + prediv_s = getreg32(STM32_RTC_PRER) & RTC_PRER_PREDIV_S_MASK; + prediv_s >>= RTC_PRER_PREDIV_S_SHIFT; + + ssr &= RTC_SSR_MASK; + + /* Maximum prediv_s is 0x7fff, thus we can multiply by 100000 and + * still fit 32-bit unsigned integer. + */ + + usecs = (((prediv_s - ssr) * 100000) / (prediv_s + 1)) * 10; + if (nsec != NULL) + { + *nsec = usecs * 1000; + } + + rtc_dumptime((FAR const struct tm *)tp, &usecs, "Returning"); +#else /* CONFIG_STM32H7_HAVE_RTC_SUBSECONDS */ + rtc_dumptime((FAR const struct tm *)tp, NULL, "Returning"); +#endif + + return OK; +} + +/**************************************************************************** + * Name: up_rtc_getdatetime + * + * Description: + * Get the current date and time from the date/time RTC. This interface + * is only supported by the date/time RTC hardware implementation. + * It is used to replace the system timer. It is only used by the RTOS + * during initialization to set up the system time when CONFIG_RTC and + * CONFIG_RTC_DATETIME are selected (and CONFIG_RTC_HIRES is not). + * + * NOTE: Some date/time RTC hardware is capability of sub-second accuracy. + * That sub-second accuracy is lost in this interface. However, since the + * system time is reinitialized on each power-up/reset, there will be no + * timing inaccuracy in the long run. + * + * Input Parameters: + * tp - The location to return the high resolution time value. + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_STM32H7_HAVE_RTC_SUBSECONDS +int up_rtc_getdatetime(FAR struct tm *tp) +{ + return stm32_rtc_getdatetime_with_subseconds(tp, NULL); +} +#endif + +/**************************************************************************** + * Name: up_rtc_getdatetime_with_subseconds + * + * Description: + * Get the current date and time from the date/time RTC. This interface + * is only supported by the date/time RTC hardware implementation. + * It is used to replace the system timer. It is only used by the RTOS during + * initialization to set up the system time when CONFIG_RTC and CONFIG_RTC_DATETIME + * are selected (and CONFIG_RTC_HIRES is not). + * + * NOTE: This interface exposes sub-second accuracy capability of RTC hardware. + * This interface allow maintaining timing accuracy when system time needs constant + * resynchronization with RTC, for example with board level power-save mode utilizing + * deep-sleep modes such as STOP on STM32 MCUs. + * + * Input Parameters: + * tp - The location to return the high resolution time value. + * nsec - The location to return the subsecond time value. + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_ARCH_HAVE_RTC_SUBSECONDS +# ifndef CONFIG_STM32H7_HAVE_RTC_SUBSECONDS +# error "Invalid config, enable CONFIG_STM32H7_HAVE_RTC_SUBSECONDS." +# endif +int up_rtc_getdatetime_with_subseconds(FAR struct tm *tp, FAR long *nsec) +{ + return stm32_rtc_getdatetime_with_subseconds(tp, nsec); +} +#endif + +/**************************************************************************** + * Name: stm32_rtc_setdatetime + * + * Description: + * Set the RTC to the provided time. RTC implementations which provide + * up_rtc_getdatetime() (CONFIG_RTC_DATETIME is selected) should provide + * this function. + * + * Input Parameters: + * tp - the time to use + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +int stm32_rtc_setdatetime(FAR const struct tm *tp) +{ + uint32_t tr; + uint32_t dr; + int ret; + + rtc_dumptime(tp, NULL, "Setting time"); + + /* Then write the broken out values to the RTC */ + + /* Convert the struct tm format to RTC time register fields. + * All of the ranges of values correspond between struct tm and the + * time register. + */ + + tr = (rtc_bin2bcd(tp->tm_sec) << RTC_TR_SU_SHIFT) | + (rtc_bin2bcd(tp->tm_min) << RTC_TR_MNU_SHIFT) | + (rtc_bin2bcd(tp->tm_hour) << RTC_TR_HU_SHIFT); + tr &= ~RTC_TR_RESERVED_BITS; + + /* Now convert the fields in struct tm format to the RTC date register + * fields: + * + * Days: 1-31 match in both cases. + * Month: STM32 is 1-12, struct tm is 0-11. + * Years: STM32 is 00-99, struct tm is years since 1900. + * WeekDay: STM32 is 1 = Mon - 7 = Sun + * + * Issue: I am not sure what the STM32 years mean. Are these the + * years 2000-2099? I'll assume so. + */ + + dr = (rtc_bin2bcd(tp->tm_mday) << RTC_DR_DU_SHIFT) | + ((rtc_bin2bcd(tp->tm_mon + 1)) << RTC_DR_MU_SHIFT) | +#if defined(CONFIG_LIBC_LOCALTIME) || defined(CONFIG_TIME_EXTENDED) + ((tp->tm_wday == 0 ? 7 : (tp->tm_wday & 7)) << RTC_DR_WDU_SHIFT) | +#endif + ((rtc_bin2bcd(tp->tm_year - 100)) << RTC_DR_YU_SHIFT); + + dr &= ~RTC_DR_RESERVED_BITS; + + /* Disable the write protection for RTC registers */ + + rtc_wprunlock(); + + /* Set Initialization mode */ + + ret = rtc_enterinit(); + if (ret == OK) + { + /* Set the RTC TR and DR registers */ + + putreg32(tr, STM32_RTC_TR); + putreg32(dr, STM32_RTC_DR); + + /* Exit Initialization mode and wait for the RTC Time and Date + * registers to be synchronized with RTC APB clock. + */ + + rtc_exitinit(); + ret = rtc_synchwait(); + } + + /* Remember that the RTC is initialized and had its time set. */ + + if (getreg32(RTC_MAGIC_REG) != RTC_MAGIC_TIME_SET) + { + stm32_pwr_enablebkp(true); + putreg32(RTC_MAGIC_TIME_SET, RTC_MAGIC_REG); + stm32_pwr_enablebkp(false); + } + + /* Re-enable the write protection for RTC registers */ + + rtc_wprlock(); + rtc_dumpregs("New time setting"); + return ret; +} + +/**************************************************************************** + * Name: stm32_rtc_havesettime + * + * Description: + * Check if RTC time has been set. + * + * Returned Value: + * Returns true if RTC date-time have been previously set. + * + ****************************************************************************/ + +bool stm32_rtc_havesettime(void) +{ + return getreg32(RTC_MAGIC_REG) == RTC_MAGIC_TIME_SET; +} + +/**************************************************************************** + * Name: up_rtc_settime + * + * Description: + * Set the RTC to the provided time. All RTC implementations must be able + * to set their time based on a standard timespec. + * + * Input Parameters: + * tp - the time to use + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +int up_rtc_settime(FAR const struct timespec *tp) +{ + FAR struct tm newtime; + + /* Break out the time values (not that the time is set only to units of + * seconds) + */ + + (void)gmtime_r(&tp->tv_sec, &newtime); + return stm32_rtc_setdatetime(&newtime); +} + +/**************************************************************************** + * Name: stm32_rtc_setalarm + * + * Description: + * Set an alarm to an absolute time using associated hardware. + * + * Input Parameters: + * alminfo - Information about the alarm configuration. + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +int stm32_rtc_setalarm(FAR struct alm_setalarm_s *alminfo) +{ + FAR struct alm_cbinfo_s *cbinfo; + rtc_alarmreg_t alarmreg; + int ret = -EINVAL; + static bool once = false; + + DEBUGASSERT(alminfo != NULL); + DEBUGASSERT(RTC_ALARM_LAST > alminfo->as_id); + + /* Configure RTC interrupt to catch alarm interrupts. All RTC interrupts + * are connected to the EXTI controller. To enable the RTC Alarm + * interrupt, the following sequence is required: + * + * 1. Configure and enable the EXTI Line 17 RTC ALARM in interrupt mode + * and select the rising edge sensitivity. + * For STM32H7: + * EXTI line 18 RTC Tamper, Timestamp & RCC LSECSS + * EXTI line 19 RTC Wakeup timer + * 2. Configure and enable the RTC_Alarm IRQ channel in the NVIC. + * 3. Configure the RTC to generate RTC alarms (Alarm A or Alarm B). + */ + + if (!once) + { + once = true; + (void)stm32_exti_alarm(true, false, true, stm32_rtc_alarm_handler, NULL); + } + + /* REVISIT: Should test that the time is in the future */ + + rtc_dumptime(&alminfo->as_time, NULL, "New alarm time"); + + /* Break out the values to the HW alarm register format. The values in + * all STM32 fields match the fields of struct tm in this case. Notice + * that the alarm is limited to one month. + */ + + alarmreg = (rtc_bin2bcd(alminfo->as_time.tm_sec) << RTC_ALRMR_SU_SHIFT) | + (rtc_bin2bcd(alminfo->as_time.tm_min) << RTC_ALRMR_MNU_SHIFT) | + (rtc_bin2bcd(alminfo->as_time.tm_hour) << RTC_ALRMR_HU_SHIFT) | + (rtc_bin2bcd(alminfo->as_time.tm_mday) << RTC_ALRMR_DU_SHIFT); + + /* Set the alarm in hardware and enable interrupts */ + + switch (alminfo->as_id) + { + case RTC_ALARMA: + { + cbinfo = &g_alarmcb[RTC_ALARMA]; + cbinfo->ac_cb = alminfo->as_cb; + cbinfo->ac_arg = alminfo->as_arg; + + ret = rtchw_set_alrmar(alarmreg | RTC_ALRMR_ENABLE); + if (ret < 0) + { + cbinfo->ac_cb = NULL; + cbinfo->ac_arg = NULL; + } + } + break; + +#if CONFIG_RTC_NALARMS > 1 + case RTC_ALARMB: + { + cbinfo = &g_alarmcb[RTC_ALARMB]; + cbinfo->ac_cb = alminfo->as_cb; + cbinfo->ac_arg = alminfo->as_arg; + + ret = rtchw_set_alrmbr(alarmreg | RTC_ALRMR_ENABLE); + if (ret < 0) + { + cbinfo->ac_cb = NULL; + cbinfo->ac_arg = NULL; + } + } + break; +#endif + + default: + rtcerr("ERROR: Invalid ALARM%d\n", alminfo->as_id); + break; + } + + rtc_dumpregs("After alarm setting"); + + return ret; +} +#endif + +/**************************************************************************** + * Name: stm32_rtc_cancelalarm + * + * Description: + * Cancel an alarm. + * + * Input Parameters: + * alarmid - Identifies the alarm to be canceled + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +int stm32_rtc_cancelalarm(enum alm_id_e alarmid) +{ + int ret = -EINVAL; + + DEBUGASSERT(RTC_ALARM_LAST > alarmid); + + /* Cancel the alarm in hardware and disable interrupts */ + + switch (alarmid) + { + case RTC_ALARMA: + { + /* Cancel the global callback function */ + + g_alarmcb[alarmid].ac_cb = NULL; + g_alarmcb[alarmid].ac_arg = NULL; + + /* Disable the write protection for RTC registers */ + + rtc_wprunlock(); + + /* Disable RTC alarm and interrupt */ + + modifyreg32(STM32_RTC_CR, (RTC_CR_ALRAE | RTC_CR_ALRAIE), 0); + + ret = rtchw_check_alrawf(); + if (ret < 0) + { + goto errout_with_wprunlock; + } + + /* Unset the alarm */ + + putreg32(-1, STM32_RTC_ALRMAR); + modifyreg32(STM32_RTC_ISR, RTC_ISR_ALRAF, 0); + rtc_wprlock(); + ret = OK; + } + break; + +#if CONFIG_RTC_NALARMS > 1 + case RTC_ALARMB: + { + /* Cancel the global callback function */ + + g_alarmcb[alarmid].ac_cb = NULL; + g_alarmcb[alarmid].ac_arg = NULL; + + /* Disable the write protection for RTC registers */ + + rtc_wprunlock(); + + /* Disable RTC alarm and interrupt */ + + modifyreg32(STM32_RTC_CR, (RTC_CR_ALRBE | RTC_CR_ALRBIE), 0); + + ret = rtchw_check_alrbwf(); + if (ret < 0) + { + goto errout_with_wprunlock; + } + + /* Unset the alarm */ + + putreg32(-1, STM32_RTC_ALRMBR); + modifyreg32(STM32_RTC_ISR, RTC_ISR_ALRBF, 0); + rtc_wprlock(); + ret = OK; + } + break; +#endif + + default: + rtcerr("ERROR: Invalid ALARM%d\n", alarmid); + break; + } + + return ret; + +errout_with_wprunlock: + rtc_wprlock(); + return ret; +} +#endif + +/**************************************************************************** + * Name: stm32_rtc_rdalarm + * + * Description: + * Query an alarm configured in hardware. + * + * Input Parameters: + * alminfo - Information about the alarm configuration. + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +int stm32_rtc_rdalarm(FAR struct alm_rdalarm_s *alminfo) +{ + rtc_alarmreg_t alarmreg; + int ret = -EINVAL; + + DEBUGASSERT(alminfo != NULL); + DEBUGASSERT(RTC_ALARM_LAST > alminfo->ar_id); + + switch (alminfo->ar_id) + { + case RTC_ALARMA: + { + alarmreg = STM32_RTC_ALRMAR; + ret = stm32_rtc_getalarmdatetime(alarmreg, + (struct tm *)alminfo->ar_time); + } + break; + +#if CONFIG_RTC_NALARMS > 1 + case RTC_ALARMB: + { + alarmreg = STM32_RTC_ALRMBR; + ret = stm32_rtc_getalarmdatetime(alarmreg, + (struct tm *)alminfo->ar_time); + } + break; +#endif + + default: + rtcerr("ERROR: Invalid ALARM%d\n", alminfo->ar_id); + break; + } + + return ret; +} +#endif + +/**************************************************************************** + * Name: stm32_rtc_wakeup_handler + * + * Description: + * RTC WAKEUP interrupt service routine through the EXTI line + * + * Input Parameters: + * irq - The IRQ number that generated the interrupt + * + * Returned Value: + * Zero (OK) on success; A negated errno value on failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_PERIODIC +static int stm32_rtc_wakeup_handler(int irq, FAR void *context, + FAR void *arg) +{ + uint32_t regval = 0; + + stm32_pwr_enablebkp(true); + + regval = getreg32(STM32_RTC_ISR); + regval &= ~RTC_ISR_WUTF; + putreg32(regval, STM32_RTC_ISR); + + stm32_pwr_enablebkp(false); + + if (g_wakeupcb != NULL) + { + g_wakeupcb(); + } + + return OK; +} +#endif + +/**************************************************************************** + * Name: rtc_enable_wakeup + * + * Description: + * Enable periodic wakeup interrupts + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_PERIODIC +static inline void rtc_enable_wakeup(void) +{ + if (!g_wakeup_enabled) + { + (void)stm32_exti_wakeup(true, false, true, stm32_rtc_wakeup_handler, + NULL); + g_wakeup_enabled = true; + } +} +#endif + +/************************************************************************************ + * Name: rtc_set_wcksel + * + * Description: + * Sets RTC wakeup clock selection value + * + ************************************************************************************/ + +#ifdef CONFIG_RTC_PERIODIC +static inline void rtc_set_wcksel(unsigned int wucksel) +{ + uint32_t regval = 0; + + regval = getreg32(STM32_RTC_CR); + regval &= ~RTC_CR_WUCKSEL_MASK; + regval |= wucksel; + putreg32(regval, STM32_RTC_CR); +} +#endif + +/**************************************************************************** + * Name: stm32_rtc_setperiodic + * + * Description: + * Set a periodic RTC wakeup + * + * Input Parameters: + * period - Time to sleep between wakeups + * callback - Function to call when the period expires. + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_PERIODIC +int stm32_rtc_setperiodic(FAR const struct timespec *period, + wakeupcb_t callback) +{ + unsigned int wutr_val; + int ret; + int timeout; + uint32_t regval; + uint32_t secs; + uint32_t millisecs; + +#if defined(CONFIG_STM32H7_RTC_HSECLOCK) +# error "Periodic wakeup not available for HSE" +#elif defined(CONFIG_STM32H7_RTC_LSICLOCK) +# error "Periodic wakeup not available for LSI (and it is too inaccurate!)" +#elif defined(CONFIG_STM32H7_RTC_LSECLOCK) + const uint32_t rtc_div16_max_msecs = 16 * 1000 * 0xffffU / STM32_LSE_FREQUENCY; +#else +# error "No clock for RTC!" +#endif + + /* Lets use RTC wake-up with 0.001 sec to ~18 hour range. + * + * TODO: scale to higher periods, with necessary losing some precision. + * We currently go for subseconds accuracy instead of maximum period. + */ + + if (period->tv_sec > 0xffffU || + (period->tv_sec == 0xffffU && period->tv_nsec > 0)) + { + /* More than max. */ + + secs = 0xffffU; + millisecs = secs * 1000; + } + else + { + secs = period->tv_sec; + millisecs = secs * 1000 + period->tv_nsec / NSEC_PER_MSEC; + } + + if (millisecs == 0) + { + return -EINVAL; + } + + /* Make sure the alarm interrupt is enabled at the NVIC */ + + rtc_enable_wakeup(); + + rtc_wprunlock(); + + /* Clear WUTE in RTC_CR to disable the wakeup timer */ + + regval = getreg32(STM32_RTC_CR); + regval &= ~RTC_CR_WUTE; + putreg32(regval, STM32_RTC_CR); + + /* Poll WUTWF until it is set in RTC_ISR (takes around 2 RTCCLK clock + * cycles) + */ + + ret = -ETIMEDOUT; + for (timeout = 0; timeout < SYNCHRO_TIMEOUT; timeout++) + { + regval = getreg32(STM32_RTC_ISR); + if ((regval & RTC_ISR_WUTWF) != 0) + { + /* Synchronized */ + + ret = OK; + break; + } + } + + /* Set callback function pointer. */ + + g_wakeupcb = callback; + + if (millisecs <= rtc_div16_max_msecs) + { + unsigned int ticks; + + /* Select wake-up with 32768/16 hz counter. */ + + rtc_set_wcksel(RTC_CR_WUCKSEL_RTCDIV16); + + /* Get number of ticks. */ + + ticks = millisecs * STM32_LSE_FREQUENCY / (16 * 1000); + + /* Wake-up is after WUT+1 ticks. */ + + wutr_val = ticks - 1; + } + else + { + /* Select wake-up with 1hz counter. */ + + rtc_set_wcksel(RTC_CR_WUCKSEL_CKSPRE); + + /* Wake-up is after WUT+1 ticks. */ + + wutr_val = secs - 1; + } + + /* Program the wakeup auto-reload value WUT[15:0], and the wakeup clock + * selection. + */ + + putreg32(wutr_val, STM32_RTC_WUTR); + + regval = getreg32(STM32_RTC_CR); + regval |= RTC_CR_WUTIE | RTC_CR_WUTE; + putreg32(regval, STM32_RTC_CR); + + /* Just in case resets the WUTF flag in RTC_ISR */ + + regval = getreg32(STM32_RTC_ISR); + regval &= ~RTC_ISR_WUTF; + putreg32(regval, STM32_RTC_ISR); + + rtc_wprlock(); + + return ret; +} +#endif + +/**************************************************************************** + * Name: stm32_rtc_cancelperiodic + * + * Description: + * Cancel a periodic wakeup + * + * Input Parameters: + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_PERIODIC +int stm32_rtc_cancelperiodic(void) +{ + int ret = OK; + int timeout = 0; + uint32_t regval = 0; + + rtc_wprunlock(); + + /* Clear WUTE and WUTIE in RTC_CR to disable the wakeup timer */ + + regval = getreg32(STM32_RTC_CR); + regval &= ~(RTC_CR_WUTE | RTC_CR_WUTIE); + putreg32(regval, STM32_RTC_CR); + + /* Poll WUTWF until it is set in RTC_ISR (takes around 2 RTCCLK clock + * cycles) + */ + + ret = -ETIMEDOUT; + for (timeout = 0; timeout < SYNCHRO_TIMEOUT; timeout++) + { + regval = getreg32(STM32_RTC_ISR); + if ((regval & RTC_ISR_WUTWF) != 0) + { + /* Synchronized */ + + ret = OK; + break; + } + } + + /* Clears RTC_WUTR register */ + + regval = getreg32(STM32_RTC_WUTR); + regval &= ~RTC_WUTR_MASK; + putreg32(regval, STM32_RTC_WUTR); + + rtc_wprlock(); + + return ret; +} +#endif + +#endif /* CONFIG_STM32H7_RTC */ diff --git a/arch/arm/src/stm32h7/stm32_rtc.h b/arch/arm/src/stm32h7/stm32_rtc.h new file mode 100644 index 00000000000..fb556b26dc5 --- /dev/null +++ b/arch/arm/src/stm32h7/stm32_rtc.h @@ -0,0 +1,195 @@ +/**************************************************************************** + * arch/arm/src/stm32h7/stm32_rtc.h + * + * Copyright (C) 2011 Uros Platise. All rights reserved. + * Copyright (C) 2011-2013, 2015-2019 Gregory Nutt. All rights reserved. + * Authors: Uros Platise (Original for the F1) + * Gregory Nutt (On-going support and development) + * David Sidrane + * + * 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 NuttX 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 OWNER 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_STM32H7_STM32_RTC_H +#define __ARCH_ARM_SRC_STM32H7_STM32_RTC_H + +#include + +#include "chip.h" + +/* The STMH7 family use a more traditional Realtime Clock/Calendar (RTCC) with + * broken-out data/time in BCD format. The backup registers are integrated into + * the RTCC in these families. + */ + +#include "hardware/stm32_rtcc.h" +#include "stm32_alarm.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define STM32_RTC_PRESCALER_SECOND 32767 /* Default prescaler to get a second base */ +#define STM32_RTC_PRESCALER_MIN 1 /* Maximum speed of 16384 Hz */ + +#if !defined(CONFIG_STM32H7_RTC_MAGIC) +# define CONFIG_STM32H7_RTC_MAGIC (0xfacefeed) +#endif + +#if !defined(CONFIG_STM32H7_RTC_MAGIC_TIME_SET) +# define CONFIG_STM32H7_RTC_MAGIC_TIME_SET (0xf00dface) +#endif + +#if !defined(CONFIG_STM32H7_RTC_MAGIC_REG) +# define CONFIG_STM32H7_RTC_MAGIC_REG (0) +#endif + +#define RTC_MAGIC CONFIG_STM32H7_RTC_MAGIC +#define RTC_MAGIC_TIME_SET CONFIG_STM32H7_RTC_MAGIC_TIME_SET +#define RTC_MAGIC_REG STM32_RTC_BKR(CONFIG_STM32H7_RTC_MAGIC_REG) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_rtc_getdatetime_with_subseconds + * + * Description: + * Get the current date and time from the date/time RTC. This interface + * is only supported by the date/time RTC hardware implementation. + * It is used to replace the system timer. It is only used by the RTOS + * during initialization to set up the system time when CONFIG_RTC and + * CONFIG_RTC_DATETIME are selected (and CONFIG_RTC_HIRES is not). + * + * NOTE: The sub-second accuracy is returned through 'nsec'. + * + * Input Parameters: + * tp - The location to return the high resolution time value. + * nsec - The location to return the subsecond time value. + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_STM32H7_HAVE_RTC_SUBSECONDS +int stm32_rtc_getdatetime_with_subseconds(FAR struct tm *tp, FAR long *nsec); +#endif + +/**************************************************************************** + * Name: stm32_rtc_setdatetime + * + * Description: + * Set the RTC to the provided time. RTC implementations which provide + * up_rtc_getdatetime() (CONFIG_RTC_DATETIME is selected) should provide + * this function. + * + * Input Parameters: + * tp - the time to use + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_DATETIME +struct tm; +int stm32_rtc_setdatetime(FAR const struct tm *tp); +#endif + +/**************************************************************************** + * Name: stm32_rtc_havesettime + * + * Description: + * Check if RTC time has been set. + * + * Returned Value: + * Returns true if RTC date-time have been previously set. + * + ****************************************************************************/ + +bool stm32_rtc_havesettime(void); + +/**************************************************************************** + * Name: stm32_rtc_lowerhalf + * + * Description: + * Instantiate the RTC lower half driver for the STM32. General usage: + * + * #include + * #include "stm32_rtc.h> + * + * struct rtc_lowerhalf_s *lower; + * lower = stm32_rtc_lowerhalf(); + * rtc_initialize(0, lower); + * + * Input Parameters: + * None + * + * Returned Value: + * On success, a non-NULL RTC lower interface is returned. NULL is + * returned on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_DRIVER +struct rtc_lowerhalf_s; +FAR struct rtc_lowerhalf_s *stm32_rtc_lowerhalf(void); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_STM32H7_STM32_RTC_H */ diff --git a/arch/arm/src/stm32h7/stm32_rtc_lowerhalf.c b/arch/arm/src/stm32h7/stm32_rtc_lowerhalf.c new file mode 100644 index 00000000000..90001d8fcfa --- /dev/null +++ b/arch/arm/src/stm32h7/stm32_rtc_lowerhalf.c @@ -0,0 +1,763 @@ +/**************************************************************************** + * arch/arm/src/stm32h7/stm32_rtc_lowerhalf.c + * + * Copyright (C) 2015-2016, 2018 Gregory Nutt. All rights reserved. + * Authors: Gregory Nutt + * David Sidrane + * + * 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 NuttX 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 OWNER 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include + +#include "up_arch.h" + +#include "chip.h" +#include "stm32_rtc.h" + +#ifdef CONFIG_RTC_DRIVER + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define STM32_NALARMS 2 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +struct stm32_cbinfo_s +{ + volatile rtc_alarm_callback_t cb; /* Callback when the alarm expires */ + volatile FAR void *priv; /* Private argument to accompany callback */ + uint8_t id; /* Identifies the alarm */ +}; +#endif + +/* This is the private type for the RTC state. It must be cast compatible + * with struct rtc_lowerhalf_s. + */ + +struct stm32_lowerhalf_s +{ + /* This is the contained reference to the read-only, lower-half + * operations vtable (which may lie in FLASH or ROM) + */ + + FAR const struct rtc_ops_s *ops; + + /* Data following is private to this driver and not visible outside of + * this file. + */ + + sem_t devsem; /* Threads can only exclusively access the RTC */ + +#ifdef CONFIG_RTC_ALARM + /* Alarm callback information */ + + struct stm32_cbinfo_s cbinfo[STM32_NALARMS]; +#endif + +#ifdef CONFIG_RTC_PERIODIC + /* Periodic wakeup information */ + + struct lower_setperiodic_s periodic; +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Prototypes for static methods in struct rtc_ops_s */ + +static int stm32_rdtime(FAR struct rtc_lowerhalf_s *lower, + FAR struct rtc_time *rtctime); +static int stm32_settime(FAR struct rtc_lowerhalf_s *lower, + FAR const struct rtc_time *rtctime); +static bool stm32_havesettime(FAR struct rtc_lowerhalf_s *lower); + +#ifdef CONFIG_RTC_ALARM +static int stm32_setalarm(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setalarm_s *alarminfo); +static int stm32_setrelative(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setrelative_s *alarminfo); +static int stm32_cancelalarm(FAR struct rtc_lowerhalf_s *lower, + int alarmid); +static int stm32_rdalarm(FAR struct rtc_lowerhalf_s *lower, + FAR struct lower_rdalarm_s *alarminfo); +#endif + +#ifdef CONFIG_RTC_PERIODIC +static int stm32_setperiodic(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setperiodic_s *alarminfo); +static int stm32_cancelperiodic(FAR struct rtc_lowerhalf_s *lower, int id); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ +/* STM32 RTC driver operations */ + +static const struct rtc_ops_s g_rtc_ops = +{ + .rdtime = stm32_rdtime, + .settime = stm32_settime, + .havesettime = stm32_havesettime, +#ifdef CONFIG_RTC_ALARM + .setalarm = stm32_setalarm, + .setrelative = stm32_setrelative, + .cancelalarm = stm32_cancelalarm, + .rdalarm = stm32_rdalarm, +#endif +#ifdef CONFIG_RTC_PERIODIC + .setperiodic = stm32_setperiodic, + .cancelperiodic = stm32_cancelperiodic, +#endif +#ifdef CONFIG_RTC_IOCTL + .ioctl = NULL, +#endif +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS + .destroy = NULL, +#endif +}; + +/* STM32 RTC device state */ + +static struct stm32_lowerhalf_s g_rtc_lowerhalf = +{ + .ops = &g_rtc_ops, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_alarm_callback + * + * Description: + * This is the function that is called from the RTC driver when the alarm + * goes off. It just invokes the upper half drivers callback. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static void stm32_alarm_callback(FAR void *arg, unsigned int alarmid) +{ + FAR struct stm32_lowerhalf_s *lower; + FAR struct stm32_cbinfo_s *cbinfo; + rtc_alarm_callback_t cb; + FAR void *priv; + + DEBUGASSERT(arg != NULL); + DEBUGASSERT(alarmid == RTC_ALARMA || alarmid == RTC_ALARMB); + + lower = (struct stm32_lowerhalf_s *)arg; + cbinfo = &lower->cbinfo[alarmid]; + + /* Sample and clear the callback information to minimize the window in + * time in which race conditions can occur. + */ + + cb = (rtc_alarm_callback_t)cbinfo->cb; + priv = (FAR void *)cbinfo->priv; + DEBUGASSERT(priv != NULL); + + cbinfo->cb = NULL; + cbinfo->priv = NULL; + + /* Perform the callback */ + + if (cb != NULL) + { + cb(priv, alarmid); + } +} +#endif /* CONFIG_RTC_ALARM */ + +/**************************************************************************** + * Name: stm32_rdtime + * + * Description: + * Implements the rdtime() method of the RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * rcttime - The location in which to return the current RTC time. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +static int stm32_rdtime(FAR struct rtc_lowerhalf_s *lower, + FAR struct rtc_time *rtctime) +{ + FAR struct stm32_lowerhalf_s *priv; + int ret; + + priv = (FAR struct stm32_lowerhalf_s *)lower; + + ret = nxsem_wait(&priv->devsem); + if (ret < 0) + { + return ret; + } + +#if defined(CONFIG_RTC_DATETIME) + /* This operation depends on the fact that struct rtc_time is cast + * compatible with struct tm. + */ + + ret = up_rtc_getdatetime((FAR struct tm *)rtctime); +#else + time_t timer; + + /* The resolution of time is only 1 second */ + + timer = up_rtc_time(); + + /* Convert the one second epoch time to a struct tm */ + + if (!gmtime_r(&timer, (FAR struct tm *)rtctime)) + { + int errcode = get_errno(); + DEBUGASSERT(errcode > 0); + nxsem_post(&priv->devsem); + return -errcode; + } + +#endif + nxsem_post(&priv->devsem); + return ret; +} + +/**************************************************************************** + * Name: stm32_settime + * + * Description: + * Implements the settime() method of the RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * rcttime - The new time to set + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +static int stm32_settime(FAR struct rtc_lowerhalf_s *lower, + FAR const struct rtc_time *rtctime) +{ + FAR struct stm32_lowerhalf_s *priv; + int ret; + + priv = (FAR struct stm32_lowerhalf_s *)lower; + + ret = nxsem_wait(&priv->devsem); + if (ret < 0) + { + return ret; + } + +#ifdef CONFIG_RTC_DATETIME + /* This operation depends on the fact that struct rtc_time is cast + * compatible with struct tm. + */ + + ret = stm32_rtc_setdatetime((FAR const struct tm *)rtctime); + +#else + struct timespec ts; + + /* Convert the struct rtc_time to a time_t. Here we assume that struct + * rtc_time is cast compatible with struct tm. + */ + + ts.tv_sec = mktime((FAR struct tm *)rtctime); + ts.tv_nsec = 0; + + /* Now set the time (to one second accuracy) */ + + ret = up_rtc_settime(&ts); +#endif + + nxsem_post(&priv->devsem); + return ret; +} + +/**************************************************************************** + * Name: stm32_havesettime + * + * Description: + * Implements the havesettime() method of the RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * + * Returned Value: + * Returns true if RTC date-time have been previously set. + * + ****************************************************************************/ + +static bool stm32_havesettime(FAR struct rtc_lowerhalf_s *lower) +{ + return stm32_rtc_havesettime(); +} + +/**************************************************************************** + * Name: stm32_setalarm + * + * Description: + * Set a new alarm. This function implements the setalarm() method of the + * RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * alarminfo - Provided information needed to set the alarm + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int stm32_setalarm(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setalarm_s *alarminfo) +{ + FAR struct stm32_lowerhalf_s *priv; + FAR struct stm32_cbinfo_s *cbinfo; + struct alm_setalarm_s lowerinfo; + int ret; + + /* ID0-> Alarm A; ID1 -> Alarm B */ + + DEBUGASSERT(lower != NULL && alarminfo != NULL); + DEBUGASSERT(alarminfo->id == RTC_ALARMA || alarminfo->id == RTC_ALARMB); + priv = (FAR struct stm32_lowerhalf_s *)lower; + + ret = nxsem_wait(&priv->devsem); + if (ret < 0) + { + return ret; + } + + ret = -EINVAL; + if (alarminfo->id == RTC_ALARMA || alarminfo->id == RTC_ALARMB) + { + /* Remember the callback information */ + + cbinfo = &priv->cbinfo[alarminfo->id]; + cbinfo->cb = alarminfo->cb; + cbinfo->priv = alarminfo->priv; + cbinfo->id = alarminfo->id; + + /* Set the alarm */ + + lowerinfo.as_id = alarminfo->id; + lowerinfo.as_cb = stm32_alarm_callback; + lowerinfo.as_arg = priv; + memcpy(&lowerinfo.as_time, &alarminfo->time, sizeof(struct tm)); + + /* And set the alarm */ + + ret = stm32_rtc_setalarm(&lowerinfo); + if (ret < 0) + { + cbinfo->cb = NULL; + cbinfo->priv = NULL; + } + } + + nxsem_post(&priv->devsem); + + return ret; +} +#endif + +/**************************************************************************** + * Name: stm32_setrelative + * + * Description: + * Set a new alarm relative to the current time. This function implements + * the setrelative() method of the RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * alarminfo - Provided information needed to set the alarm + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int stm32_setrelative(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setrelative_s *alarminfo) +{ + struct lower_setalarm_s setalarm; + struct tm time; + time_t seconds; + int ret = -EINVAL; + + DEBUGASSERT(lower != NULL && alarminfo != NULL); + DEBUGASSERT(alarminfo->id == RTC_ALARMA || alarminfo->id == RTC_ALARMB); + + if ((alarminfo->id == RTC_ALARMA || alarminfo->id == RTC_ALARMB) && + alarminfo->reltime > 0) + { + /* Disable pre-emption while we do this so that we don't have to worry + * about being suspended and working on an old time. + */ + + sched_lock(); + + /* Get the current time in broken out format */ + + ret = up_rtc_getdatetime(&time); + if (ret >= 0) + { + /* Convert to seconds since the epoch */ + + seconds = mktime(&time); + + /* Add the seconds offset. Add one to the number of seconds + * because we are unsure of the phase of the timer. + */ + + seconds += (alarminfo->reltime + 1); + + /* And convert the time back to broken out format */ + + (void)gmtime_r(&seconds, (FAR struct tm *)&setalarm.time); + + /* The set the alarm using this absolute time */ + + setalarm.id = alarminfo->id; + setalarm.cb = alarminfo->cb; + setalarm.priv = alarminfo->priv; + + ret = stm32_setalarm(lower, &setalarm); + } + + sched_unlock(); + } + + return ret; +} +#endif + +/**************************************************************************** + * Name: stm32_cancelalarm + * + * Description: + * Cancel the current alarm. This function implements the cancelalarm() + * method of the RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * alarminfo - Provided information needed to set the alarm + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int stm32_cancelalarm(FAR struct rtc_lowerhalf_s *lower, int alarmid) +{ + FAR struct stm32_lowerhalf_s *priv; + FAR struct stm32_cbinfo_s *cbinfo; + int ret; + + DEBUGASSERT(lower != NULL); + DEBUGASSERT(alarmid == RTC_ALARMA || alarmid == RTC_ALARMB); + priv = (FAR struct stm32_lowerhalf_s *)lower; + + ret = nxsem_wait(&priv->devsem); + if (ret < 0) + { + return ret; + } + + /* ID0-> Alarm A; ID1 -> Alarm B */ + + ret = -EINVAL; + if (alarmid == RTC_ALARMA || alarmid == RTC_ALARMB) + { + /* Nullify callback information to reduce window for race conditions */ + + cbinfo = &priv->cbinfo[alarmid]; + cbinfo->cb = NULL; + cbinfo->priv = NULL; + + /* Then cancel the alarm */ + + ret = stm32_rtc_cancelalarm((enum alm_id_e)alarmid); + } + + nxsem_post(&priv->devsem); + + return ret; +} +#endif + +/**************************************************************************** + * Name: stm32_rdalarm + * + * Description: + * Query the RTC alarm. + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * alarminfo - Provided information needed to query the alarm + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int stm32_rdalarm(FAR struct rtc_lowerhalf_s *lower, + FAR struct lower_rdalarm_s *alarminfo) +{ + struct alm_rdalarm_s lowerinfo; + int ret = -EINVAL; + + DEBUGASSERT(lower != NULL && alarminfo != NULL && alarminfo->time != NULL); + DEBUGASSERT(alarminfo->id == RTC_ALARMA || alarminfo->id == RTC_ALARMB); + + if (alarminfo->id == RTC_ALARMA || alarminfo->id == RTC_ALARMB) + { + /* Disable pre-emption while we do this so that we don't have to worry + * about being suspended and working on an old time. + */ + + sched_lock(); + + lowerinfo.ar_id = alarminfo->id; + lowerinfo.ar_time = alarminfo->time; + + ret = stm32_rtc_rdalarm(&lowerinfo); + + sched_unlock(); + } + + return ret; +} +#endif + +/**************************************************************************** + * Name: stm32_periodic_callback + * + * Description: + * This is the function that is called from the RTC driver when the + * periodic wakeup goes off. It just invokes the upper half driver's + * callback. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_PERIODIC +static int stm32_periodic_callback(void) +{ + FAR struct stm32_lowerhalf_s *lower; + struct lower_setperiodic_s *cbinfo; + rtc_wakeup_callback_t cb; + FAR void *priv; + + lower = (FAR struct stm32_lowerhalf_s *)&g_rtc_lowerhalf; + + cbinfo = &lower->periodic; + cb = (rtc_wakeup_callback_t)cbinfo->cb; + priv = (FAR void *)cbinfo->priv; + + /* Perform the callback */ + + if (cb != NULL) + { + cb(priv, 0); + } + + return OK; +} +#endif /* CONFIG_RTC_PERIODIC */ + +/**************************************************************************** + * Name: stm32_setperiodic + * + * Description: + * Set a new periodic wakeup relative to the current time, with a given + * period. This function implements the setperiodic() method of the RTC + * driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * alarminfo - Provided information needed to set the wakeup activity + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_PERIODIC +static int stm32_setperiodic(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setperiodic_s *alarminfo) +{ + FAR struct stm32_lowerhalf_s *priv; + int ret; + + DEBUGASSERT(lower != NULL && alarminfo != NULL); + priv = (FAR struct stm32_lowerhalf_s *)lower; + + ret = nxsem_wait(&priv->devsem); + if (ret < 0) + { + return ret; + } + + memcpy(&priv->periodic, alarminfo, sizeof(struct lower_setperiodic_s)); + + ret = stm32_rtc_setperiodic(&alarminfo->period, stm32_periodic_callback); + + nxsem_post(&priv->devsem); + + return ret; +} +#endif + +/**************************************************************************** + * Name: stm32_cancelperiodic + * + * Description: + * Cancel the current periodic wakeup activity. This function implements + * the cancelperiodic() method of the RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_PERIODIC +static int stm32_cancelperiodic(FAR struct rtc_lowerhalf_s *lower, int id) +{ + FAR struct stm32_lowerhalf_s *priv; + int ret; + + DEBUGASSERT(lower != NULL); + priv = (FAR struct stm32_lowerhalf_s *)lower; + + DEBUGASSERT(id == 0); + + ret = nxsem_wait(&priv->devsem); + if (ret < 0) + { + return ret; + } + + ret = stm32_rtc_cancelperiodic(); + + nxsem_post(&priv->devsem); + + return ret; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_rtc_lowerhalf + * + * Description: + * Instantiate the RTC lower half driver for the STM32. General usage: + * + * #include + * #include "stm32_rtc.h> + * + * struct rtc_lowerhalf_s *lower; + * lower = stm32_rtc_lowerhalf(); + * rtc_initialize(0, lower); + * + * Input Parameters: + * None + * + * Returned Value: + * On success, a non-NULL RTC lower interface is returned. NULL is + * returned on any failure. + * + ****************************************************************************/ + +FAR struct rtc_lowerhalf_s *stm32_rtc_lowerhalf(void) +{ + nxsem_init(&g_rtc_lowerhalf.devsem, 0, 1); + + return (FAR struct rtc_lowerhalf_s *)&g_rtc_lowerhalf; +} + +#endif /* CONFIG_RTC_DRIVER */ diff --git a/arch/arm/src/stm32h7/stm32_sdmmc.c b/arch/arm/src/stm32h7/stm32_sdmmc.c index 7d711a8fbf8..5857299fd40 100644 --- a/arch/arm/src/stm32h7/stm32_sdmmc.c +++ b/arch/arm/src/stm32h7/stm32_sdmmc.c @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/arm/src/stm32f7/stm32_sdmmc.c + * arch/arm/src/stm32h7/stm32_sdmmc.c * * Copyright (C) 2009, 2011-2017, 2019 Gregory Nutt. All rights reserved. * Authors: Gregory Nutt diff --git a/arch/arm/src/stm32h7/stm32_sdmmc.h b/arch/arm/src/stm32h7/stm32_sdmmc.h index b295a6a906d..15774501d8b 100644 --- a/arch/arm/src/stm32h7/stm32_sdmmc.h +++ b/arch/arm/src/stm32h7/stm32_sdmmc.h @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/arm/src/stm32f7/stm32_sdmmc.h + * arch/arm/src/stm32h7/stm32_sdmmc.h * * Copyright (C) 2009, 2011, 2016, 2019 Gregory Nutt. All rights reserved. * Author: Gregory Nutt diff --git a/arch/arm/src/stm32h7/stm32_tim.c b/arch/arm/src/stm32h7/stm32_tim.c index 362584501ca..6efe2e8e95a 100644 --- a/arch/arm/src/stm32h7/stm32_tim.c +++ b/arch/arm/src/stm32h7/stm32_tim.c @@ -1,5 +1,5 @@ /*************************************************************************** - * arm/arm/src/stm32f7/stm32_tim.c + * arm/arm/src/stm32h7/stm32_tim.c * * Copyright (C) 2011 Uros Platise. All rights reserved. * Author: Uros Platise diff --git a/boards/arm/stm32h7/nucleo-h743zi/src/nucleo-h743zi.h b/boards/arm/stm32h7/nucleo-h743zi/src/nucleo-h743zi.h index 785e87c8af9..a250b037ef9 100644 --- a/boards/arm/stm32h7/nucleo-h743zi/src/nucleo-h743zi.h +++ b/boards/arm/stm32h7/nucleo-h743zi/src/nucleo-h743zi.h @@ -1,8 +1,9 @@ /************************************************************************************ * boards/nucleo-h743zi/src/nucleo-h743zi.h * -# Copyright (C) 2017 Gwenhael Goavec-Merou. All rights reserved. -# Author: Gwenhael Goavec-Merou +# Copyright (C) 2017, 2019 Gwenhael Goavec-Merou. All rights reserved. +# Authors: Gwenhael Goavec-Merou + * David Sidrane * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -59,6 +60,7 @@ # endif #endif +#define HAVE_RTC_DRIVER 1 /* Configuration ********************************************************************/ /* LED * diff --git a/boards/arm/stm32h7/nucleo-h743zi/src/stm32_bringup.c b/boards/arm/stm32h7/nucleo-h743zi/src/stm32_bringup.c index bad557f09ad..a30bb064aa8 100644 --- a/boards/arm/stm32h7/nucleo-h743zi/src/stm32_bringup.c +++ b/boards/arm/stm32h7/nucleo-h743zi/src/stm32_bringup.c @@ -50,6 +50,11 @@ # include #endif +#ifdef HAVE_RTC_DRIVER +# include +# include "stm32_rtc.h" +#endif + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -133,6 +138,9 @@ static void stm32_i2ctool(void) int stm32_bringup(void) { int ret = OK; +#ifdef HAVE_RTC_DRIVER + FAR struct rtc_lowerhalf_s *lower; +#endif UNUSED(ret); @@ -160,6 +168,32 @@ int stm32_bringup(void) } #endif /* CONFIG_FS_PROCFS */ +#ifdef HAVE_RTC_DRIVER + /* Instantiate the STM32 lower-half RTC driver */ + + lower = stm32_rtc_lowerhalf(); + if (!lower) + { + syslog(LOG_ERR, + "ERROR: Failed to instantiate the RTC lower-half driver\n"); + return -ENOMEM; + } + else + { + /* Bind the lower half driver and register the combined RTC driver + * as /dev/rtc0 + */ + + ret = rtc_initialize(0, lower); + if (ret < 0) + { + syslog(LOG_ERR, + "ERROR: Failed to bind/register the RTC driver: %d\n", ret); + return ret; + } + } +#endif + #ifdef CONFIG_BUTTONS /* Register the BUTTON driver */