GPS Device
Loading...
Searching...
No Matches
stm32f401re_rtc.c
Go to the documentation of this file.
1
11
12#include "stm32f401re_rtc.h"
13#include "err.h"
14#include "stm32f401re_rcc.h"
15#include "common.h"
16#include "stm32f401re.h"
17
26#define RTC_BKP_DOMAIN_RST_INDICATOR_BKPxR 0
27
35#define RTC_BKP_DOMAIN_RST_INDICATOR_PATTERN 0xABCD
36
39
40/* ---- Forward declaration for internal helper ---- */
41static void rtc_set_write_protection(EN_STATUS_te en_status);
42
47
50 if(initialized) {
52 }
53
54 // Enable PWR clock to allow access to the backup domain
56
57 // Enable backup domain write access
58 PWR->PWR_CR |= (1 << PWR_CR_DBP);
59
60 // Check sentinel: if present, the RTC was already configured before this reset
64 {
66 }
67
69
70 // Start LSE oscillator and wait for it to stabilize
71 RCC->RCC_BDCR |= (1 << RCC_BDCR_LSEON);
72 while(!(RCC->RCC_BDCR & (1 << RCC_BDCR_LSERDY)));
73
74 // Select LSE as the RTC clock source
75 RCC->RCC_BDCR &= ~(0x3 << RCC_BDCR_RTCSEL);
76 RCC->RCC_BDCR |= (0x1 << RCC_BDCR_RTCSEL);
77
78 // Enable RTC
79 RCC->RCC_BDCR |= (1 << RCC_BDCR_RTCEN);
80
81 // Enter INIT mode and wait for INITF confirmation
82 RTC->RTC_ISR |= (1 << RTC_ISR_INIT);
83 while(!(RTC->RTC_ISR & (1 << RTC_ISR_INITF)));
84
85 // 24-hour format, prescalers for 1 Hz tick from 32.768 kHz LSE:
86 // f_ck_apre = LSE / (PREDIV_A + 1) = 32768 / 128 = 256 Hz
87 // f_ck_spre = f_ck_apre / (PREDIV_S + 1) = 256 / 256 = 1 Hz
88 RTC->RTC_CR &= ~(1 << RTC_CR_FMT);
89 RTC->RTC_PRER =
90 (127 << RTC_PRER_PREDIV_A) |
91 (255 << RTC_PRER_PREDIV_S);
92
93 // Exit INIT mode
94 RTC->RTC_ISR &= ~(1 << RTC_ISR_INIT);
95 while(RTC->RTC_ISR & (1 << RTC_ISR_INITF));
96
97 // Write sentinel to backup register to mark initialization complete
100
102
103 initialized = true;
104
105 return ERR_OK;
106}
107
109void rtc_set_calendar(CALENDAR_ts const *date) {
111
112 RTC->RTC_ISR |= (1 << RTC_ISR_INIT);
113 while(!(RTC->RTC_ISR & (1 << RTC_ISR_INITF)));
114
115 RTC->RTC_DR =
116 ((date->date % 10) << RTC_DR_DU) |
117 ((date->date / 10) << RTC_DR_DT) |
118 ((date->months % 10) << RTC_DR_MU) |
119 ((date->months / 10) << RTC_DR_MT) |
120 ((date->week_days) << RTC_DR_WDU) |
121 (((date->year - 2000) % 10) << RTC_DR_YU) |
122 (((date->year - 2000) / 10) << RTC_DR_YT);
123
124 RTC->RTC_ISR &= ~(1 << RTC_ISR_INIT);
125 while(RTC->RTC_ISR & (1 << RTC_ISR_INITF));
126
128}
129
131void rtc_set_time(TIME_ts const *time) {
133
134 RTC->RTC_ISR |= (1 << RTC_ISR_INIT);
135 while(!(RTC->RTC_ISR & (1 << RTC_ISR_INITF)));
136
137 RTC->RTC_TR =
138 (DEC_TO_BCD(time->hours) << RTC_TR_HU) |
139 (DEC_TO_BCD(time->minutes) << RTC_TR_MNU) |
140 (DEC_TO_BCD(time->seconds) << RTC_TR_SU);
141
142 RTC->RTC_ISR &= ~(1 << RTC_ISR_INIT);
143 while(RTC->RTC_ISR & (1 << RTC_ISR_INITF));
144
146}
147
150 uint32_t tr1, tr2;
151
152 // Double-read to ensure consistency: reading DR after TR unlocks the shadow
153 // registers and allows TR to be read again safely
154 do {
155 tr1 = RTC->RTC_TR;
156 (void)RTC->RTC_DR;
157 tr2 = RTC->RTC_TR;
158 } while(tr1 != tr2);
159
160 time->seconds = BCD_TO_DEC(tr1 & 0x7F);
161 time->minutes = BCD_TO_DEC((tr1 >> RTC_TR_MNU) & 0x7F);
162 time->hours = BCD_TO_DEC((tr1 >> RTC_TR_HU) & 0x7F);
163}
164
166
171
187 if(en_status == ENABLE) {
188 RTC->RTC_WPR = 0xFF; // Any invalid key re-enables write protection
189 }
190 else if(en_status == DISABLE) {
191 RTC->RTC_WPR = 0xCA; // First key
192 RTC->RTC_WPR = 0x53; // Second key — unlocks write access
193 }
194}
195
Common utility module public API.
System-wide error code definitions.
#define DEC_TO_BCD(DEC)
Converts a decimal value to its BCD-encoded byte equivalent.
Definition common.h:54
#define BCD_TO_DEC(BCD)
Converts a BCD-encoded byte to its decimal equivalent.
Definition common.h:47
EN_STATUS_te
Represents an enabled or disabled state.
Definition common.h:95
@ ENABLE
Definition common.h:100
@ DISABLE
Definition common.h:97
ERR_te
Standard return type used by all public API functions.
Definition err.h:35
@ ERR_OK
Definition err.h:36
@ ERR_MODULE_ALREADY_INITIALIZED
Definition err.h:54
void rcc_set_pclk_apb1(RCC_APB1ENR_te periph_position, EN_STATUS_te en_status)
Enables or disables the peripheral clock for an APB1 peripheral.
static void rtc_set_write_protection(EN_STATUS_te en_status)
Enables or disables write protection of the RTC registers.
void rtc_get_time(TIME_ts *time)
Reads the current time from the RTC.
void rtc_set_calendar(CALENDAR_ts const *date)
Sets the RTC calendar (date and weekday).
void rtc_set_time(TIME_ts const *time)
Sets the RTC time (hours, minutes, seconds).
ERR_te rtc_init(void)
Initializes the RTC peripheral.
#define PWR
#define RTC
#define RCC
@ RTC_PRER_PREDIV_S
@ RTC_PRER_PREDIV_A
@ RTC_CR_FMT
@ RCC_BDCR_LSEON
@ RCC_BDCR_LSERDY
@ RCC_BDCR_RTCSEL
@ RCC_BDCR_RTCEN
@ PWR_CR_DBP
@ RTC_ISR_INIT
@ RTC_ISR_INITF
@ RTC_TR_SU
@ RTC_TR_MNU
@ RTC_TR_HU
@ RCC_APB1ENR_PWREN
@ RTC_DR_MT
@ RTC_DR_MU
@ RTC_DR_WDU
@ RTC_DR_YU
@ RTC_DR_DT
@ RTC_DR_DU
@ RTC_DR_YT
STM32F401RE MCU-specific peripheral register definitions and bit position enumerations.
STM32F401RE RCC driver public API.
#define RTC_BKP_DOMAIN_RST_INDICATOR_PATTERN
Sentinel value written to BKP0R after successful RTC initialization.
#define RTC_BKP_DOMAIN_RST_INDICATOR_BKPxR
Backup register index used to store the initialization sentinel pattern.
bool initialized
True after rtc_init has completed successfully in this boot session.
STM32F401RE RTC driver public API.
Holds a calendar date (year, month, day, weekday).
MONTHS_te months
WEEK_DAYS_te week_days
Holds a time-of-day value (hours, minutes, seconds).
uint8_t seconds
uint8_t hours
uint8_t minutes