@@ -53,6 +53,16 @@ LOG_MODULE_REGISTER(rtc_stm32, CONFIG_RTC_LOG_LEVEL);
5353#define HW_SUBSECOND_SUPPORT 1
5454#endif
5555
56+ /* STM32 devices that support subsecond alarms (require RTC_ALRMASSR/RTC_ALRMBSSR registers) */
57+ #if defined(CONFIG_SOC_SERIES_STM32F1X ) || defined(CONFIG_SOC_SERIES_STM32F2X ) \
58+ || defined(CONFIG_SOC_SERIES_STM32L1X ) || defined(CONFIG_SOC_SERIES_STM32C0X )
59+ /* STM32F1, STM32F2, STM32L1, and STM32C0 series do not support subsecond alarms */
60+ #define HW_SUBSECOND_ALARM_SUPPORT (0)
61+ #else
62+ /* STM32F3, STM32F4, STM32L0, STM32L4, STM32H7, STM32G0, STM32G4, STM32WL5, STM32WB, STM32U5 support subsecond alarms */
63+ #define HW_SUBSECOND_ALARM_SUPPORT (1)
64+ #endif
65+
5666/* RTC start time: 1st, Jan, 2000 */
5767#define RTC_YEAR_REF 2000
5868/* struct tm start time: 1st, Jan, 1900 */
@@ -94,7 +104,8 @@ LOG_MODULE_REGISTER(rtc_stm32, CONFIG_RTC_LOG_LEVEL);
94104#define RTC_STM32_SUPPORTED_ALARM_FIELDS \
95105 (RTC_ALARM_TIME_MASK_SECOND | RTC_ALARM_TIME_MASK_MINUTE \
96106 | RTC_ALARM_TIME_MASK_HOUR | RTC_ALARM_TIME_MASK_WEEKDAY \
97- | RTC_ALARM_TIME_MASK_MONTHDAY)
107+ | RTC_ALARM_TIME_MASK_MONTHDAY \
108+ | (HW_SUBSECOND_ALARM_SUPPORT ? RTC_ALARM_TIME_MASK_NSEC : 0))
98109
99110#define RTC_STM32_EXTI_LINE_NUM DT_INST_PROP_OR(0, alrm_exti_line, 0)
100111
@@ -701,15 +712,56 @@ static int rtc_stm32_get_time(const struct device *dev, struct rtc_time *timeptr
701712 return 0 ;
702713}
703714
715+ #if HW_SUBSECOND_ALARM_SUPPORT
716+ /* Subsecond conversion functions */
717+
718+ /**
719+ * @brief Convert nanoseconds to RTC subsecond register value
720+ * @param nsec Nanoseconds (0-999999999)
721+ * @param sync_prescaler RTC sync prescaler value
722+ * @return RTC subsecond register value
723+ */
724+ static inline uint32_t rtc_stm32_nsec_to_subsecond (uint32_t nsec , uint32_t sync_prescaler )
725+ {
726+ /* Convert nanoseconds to RTC subsecond register value
727+ * Formula: rtc_subsecond = sync_prescaler - (nsec * (sync_prescaler + 1)) / 1000000000
728+ */
729+ uint64_t temp = (uint64_t )nsec * (sync_prescaler + 1 );
730+ return sync_prescaler - (uint32_t )(temp / 1000000000L );
731+ }
732+
733+ /**
734+ * @brief Convert RTC subsecond register value to nanoseconds
735+ * @param rtc_subsecond RTC subsecond register value
736+ * @param sync_prescaler RTC sync prescaler value
737+ * @return Nanoseconds (0-999999999)
738+ */
739+ static inline uint32_t rtc_stm32_subsecond_to_nsec (uint32_t rtc_subsecond , uint32_t sync_prescaler )
740+ {
741+ /* Convert RTC subsecond register value to nanoseconds
742+ * Formula: nsec = ((sync_prescaler - rtc_subsecond) * 1000000000) / (sync_prescaler + 1)
743+ */
744+ uint64_t temp = ((uint64_t )(sync_prescaler - rtc_subsecond )) * 1000000000L ;
745+ return (uint32_t )(temp / (sync_prescaler + 1 ));
746+ }
747+ #endif /* HW_SUBSECOND_ALARM_SUPPORT */
748+
704749#ifdef STM32_RTC_ALARM_ENABLED
705- static void rtc_stm32_alarm_get_alrm_time (uint16_t id , struct rtc_time * timeptr )
750+ static inline void rtc_stm32_get_ll_alrm_time (uint16_t id , struct rtc_time * timeptr ,
751+ uint32_t sync_prescaler )
706752{
707753 if (id == RTC_STM32_ALRM_A ) {
708754 timeptr -> tm_sec = bcd2bin (LL_RTC_ALMA_GetSecond (RTC ));
709755 timeptr -> tm_min = bcd2bin (LL_RTC_ALMA_GetMinute (RTC ));
710756 timeptr -> tm_hour = bcd2bin (LL_RTC_ALMA_GetHour (RTC ));
711757 timeptr -> tm_wday = bcd2bin (LL_RTC_ALMA_GetWeekDay (RTC ));
712758 timeptr -> tm_mday = bcd2bin (LL_RTC_ALMA_GetDay (RTC ));
759+ #if HW_SUBSECOND_ALARM_SUPPORT
760+ uint32_t rtc_subsecond = LL_RTC_ALMA_GetSubSecond (RTC );
761+ timeptr -> tm_nsec = rtc_stm32_subsecond_to_nsec (rtc_subsecond , sync_prescaler );
762+ #else
763+ timeptr -> tm_nsec = 0 ;
764+ #endif
713765 return ;
714766 }
715767#if RTC_STM32_ALARMS_COUNT > 1
@@ -719,6 +771,12 @@ static void rtc_stm32_alarm_get_alrm_time(uint16_t id, struct rtc_time *timeptr)
719771 timeptr -> tm_hour = bcd2bin (LL_RTC_ALMB_GetHour (RTC ));
720772 timeptr -> tm_wday = bcd2bin (LL_RTC_ALMB_GetWeekDay (RTC ));
721773 timeptr -> tm_mday = bcd2bin (LL_RTC_ALMB_GetDay (RTC ));
774+ #if HW_SUBSECOND_ALARM_SUPPORT
775+ uint32_t rtc_subsecond = LL_RTC_ALMB_GetSubSecond (RTC );
776+ timeptr -> tm_nsec = rtc_stm32_subsecond_to_nsec (rtc_subsecond , sync_prescaler );
777+ #else
778+ timeptr -> tm_nsec = 0 ;
779+ #endif
722780 }
723781#endif /* RTC_STM32_ALARMS_COUNT > 1 */
724782}
@@ -773,6 +831,90 @@ static inline uint16_t rtc_stm32_alarm_get_alrm_mask(uint16_t id)
773831 return zephyr_alarm_mask ;
774832}
775833
834+ #if HW_SUBSECOND_ALARM_SUPPORT
835+ /* Subsecond register access functions */
836+
837+ /**
838+ * @brief Read RTC subsecond register (RTC_SSR)
839+ * @param rtc_subsecond Pointer to store the subsecond value
840+ * @return 0 on success, negative error code on failure
841+ */
842+ static inline int rtc_stm32_read_subsecond (uint32_t * rtc_subsecond )
843+ {
844+ if (rtc_subsecond == NULL ) {
845+ return - EINVAL ;
846+ }
847+
848+ * rtc_subsecond = LL_RTC_TIME_GetSubSecond (RTC );
849+ return 0 ;
850+ }
851+
852+ /**
853+ * @brief Read alarm subsecond register
854+ * @param id Alarm ID (RTC_STM32_ALRM_A or RTC_STM32_ALRM_B)
855+ * @param rtc_subsecond Pointer to store the subsecond value
856+ * @return 0 on success, negative error code on failure
857+ */
858+ static inline int rtc_stm32_read_alarm_subsecond (uint16_t id , uint32_t * rtc_subsecond )
859+ {
860+ if (rtc_subsecond == NULL ) {
861+ return - EINVAL ;
862+ }
863+
864+ if (id == RTC_STM32_ALRM_A ) {
865+ * rtc_subsecond = LL_RTC_ALMA_GetSubSecond (RTC );
866+ } else if (id == RTC_STM32_ALRM_B ) {
867+ * rtc_subsecond = LL_RTC_ALMB_GetSubSecond (RTC );
868+ } else {
869+ return - EINVAL ;
870+ }
871+
872+ return 0 ;
873+ }
874+
875+ static inline uint32_t rtc_stm32_alarm_get_subsecond_mask (uint16_t id )
876+ {
877+ uint32_t reg ;
878+
879+ if (id == RTC_STM32_ALRM_A ) {
880+ reg = RTC -> ALRMASSR ;
881+ } else if (id == RTC_STM32_ALRM_B ) {
882+ reg = RTC -> ALRMBSSR ;
883+ } else {
884+ return 0 ;
885+ }
886+
887+ /*
888+ * MASKSS bitfield position/width differs across STM32 series (4..6 bits),
889+ * but is consistently located starting at bit 24.
890+ */
891+ return (reg >> 24 ) & 0x3F ;
892+ }
893+
894+ /**
895+ * @brief Write alarm subsecond register
896+ * @param id Alarm ID (RTC_STM32_ALRM_A or RTC_STM32_ALRM_B)
897+ * @param rtc_subsecond Subsecond value to write
898+ * @return 0 on success, negative error code on failure
899+ */
900+ static inline int rtc_stm32_write_alarm_subsecond (uint16_t id , uint32_t rtc_subsecond )
901+ {
902+ if (id == RTC_STM32_ALRM_A ) {
903+ LL_RTC_ALMA_SetSubSecond (RTC , rtc_subsecond );
904+ /* Compare SS[14:0] (15 bits) */
905+ LL_RTC_ALMA_SetSubSecondMask (RTC , 15 );
906+ } else if (id == RTC_STM32_ALRM_B ) {
907+ LL_RTC_ALMB_SetSubSecond (RTC , rtc_subsecond );
908+ /* Compare SS[14:0] (15 bits) */
909+ LL_RTC_ALMB_SetSubSecondMask (RTC , 15 );
910+ } else {
911+ return - EINVAL ;
912+ }
913+
914+ return 0 ;
915+ }
916+ #endif /* HW_SUBSECOND_ALARM_SUPPORT */
917+
776918static int rtc_stm32_alarm_get_supported_fields (const struct device * dev , uint16_t id ,
777919 uint16_t * mask )
778920{
@@ -795,6 +937,7 @@ static int rtc_stm32_alarm_get_time(const struct device *dev, uint16_t id, uint1
795937 struct rtc_time * timeptr )
796938{
797939 struct rtc_stm32_data * data = dev -> data ;
940+ const struct rtc_stm32_config * cfg = dev -> config ;
798941 int err = 0 ;
799942
800943 if ((mask == NULL ) || (timeptr == NULL )) {
@@ -812,12 +955,20 @@ static int rtc_stm32_alarm_get_time(const struct device *dev, uint16_t id, uint1
812955 }
813956
814957 memset (timeptr , -1 , sizeof (struct rtc_time ));
815- rtc_stm32_alarm_get_alrm_time (id , timeptr );
958+ rtc_stm32_get_ll_alrm_time (id , timeptr , cfg -> sync_prescaler );
816959 * mask = rtc_stm32_alarm_get_alrm_mask (id );
960+ #if HW_SUBSECOND_ALARM_SUPPORT
961+ if (rtc_stm32_alarm_get_subsecond_mask (id ) != 0 ) {
962+ * mask |= RTC_ALARM_TIME_MASK_NSEC ;
963+ } else {
964+ timeptr -> tm_nsec = 0 ;
965+ }
966+ #else
967+ timeptr -> tm_nsec = 0 ;
968+ #endif
817969
818- LOG_DBG ("get alarm: mday = %d, wday = %d, hour = %d, min = %d, sec = %d, "
819- "mask = 0x%04x" , timeptr -> tm_mday , timeptr -> tm_wday , timeptr -> tm_hour ,
820- timeptr -> tm_min , timeptr -> tm_sec , * mask );
970+ LOG_DBG ("get alarm: %d/%d %d:%d:%d.%d mask=0x%04x" , timeptr -> tm_mday , timeptr -> tm_wday ,
971+ timeptr -> tm_hour , timeptr -> tm_min , timeptr -> tm_sec , timeptr -> tm_nsec , * mask );
821972
822973unlock :
823974 k_spin_unlock (& data -> lock , key );
@@ -829,6 +980,7 @@ static int rtc_stm32_alarm_set_time(const struct device *dev, uint16_t id, uint1
829980 const struct rtc_time * timeptr )
830981{
831982 struct rtc_stm32_data * data = dev -> data ;
983+ const struct rtc_stm32_config * cfg = dev -> config ;
832984 struct rtc_stm32_alrm * p_rtc_alrm ;
833985 int err = 0 ;
834986
@@ -917,6 +1069,23 @@ static int rtc_stm32_alarm_set_time(const struct device *dev, uint16_t id, uint1
9171069 /* Disable the write protection for RTC registers */
9181070 LL_RTC_DisableWriteProtection (RTC );
9191071
1072+ #if HW_SUBSECOND_ALARM_SUPPORT
1073+ /* Handle subsecond alarm setting if requested */
1074+ if (mask & RTC_ALARM_TIME_MASK_NSEC ) {
1075+ uint32_t rtc_subsecond = rtc_stm32_nsec_to_subsecond (timeptr -> tm_nsec , cfg -> sync_prescaler );
1076+ rtc_stm32_write_alarm_subsecond (id , rtc_subsecond );
1077+ } else {
1078+ /* Disable subsecond comparison */
1079+ if (id == RTC_STM32_ALRM_A ) {
1080+ LL_RTC_ALMA_SetSubSecond (RTC , 0 );
1081+ LL_RTC_ALMA_SetSubSecondMask (RTC , 0 );
1082+ } else if (id == RTC_STM32_ALRM_B ) {
1083+ LL_RTC_ALMB_SetSubSecond (RTC , 0 );
1084+ LL_RTC_ALMB_SetSubSecondMask (RTC , 0 );
1085+ }
1086+ }
1087+ #endif /* HW_SUBSECOND_ALARM_SUPPORT */
1088+
9201089 /* Enable Alarm */
9211090 rtc_stm32_enable_alarm (RTC , id );
9221091 /* Clear Alarm flag */
0 commit comments