DIY Logging Volt/Ampmeter
rtc.c
Go to the documentation of this file.
1 /***************************************************************************//**
2  * @file rtc.c
3  * @brief RTC functionality for high-precision logging voltage/current meter.
4  * @version 1.0
5  * @author Brecht Van Eeckhoudt
6  *
7  * ******************************************************************************
8  *
9  * @section Versions
10  *
11  * @li v1.0: Initial version.
12  *
13  * *****************************************************************************
14  *
15  * @todo
16  * **Future improvements:**@n
17  * - Init `RTC_dateTime_t` struct somewhere?
18  * - Use `rtc.wday` somewhere?
19  *
20  * ******************************************************************************
21  *
22  * @section License
23  *
24  * **Copyright (C) 2021 - Brecht Van Eeckhoudt**
25  *
26  * This program is free software: you can redistribute it and/or modify
27  * it under the terms of the **GNU General Public License** as published by
28  * the Free Software Foundation, either **version 3** of the License, or
29  * (at your option) any later version.
30  *
31  * This program is distributed in the hope that it will be useful,
32  * but WITHOUT ANY WARRANTY; without even the implied warranty of
33  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34  * GNU General Public License for more details.
35  *
36  * *A copy of the GNU General Public License can be found in the `LICENSE`
37  * file along with this source code.*
38  *
39  * @n
40  *
41  * Some methods also use code obtained from examples from STMicroelectronics.
42  *
43  * @li https://github.com/STMicroelectronics/STM32CubeF1/tree/master/Projects/STM32F103RB-Nucleo/Examples_LL/RTC/RTC_Calendar
44  *
45  * **Copyright (c) 2020 STMicroelectronics. All rights reserved.**
46  *
47  * These sections are licensed by ST under BSD 3-Clause license, the "License";
48  * One may not use these example files except in compliance with the License.
49  * One may obtain a copy of the License at: opensource.org/licenses/BSD-3-Clause
50  *
51  * @n
52  *
53  * Some methods also use code obtained from https://github.com/mkdxdx/stm32f103_logger
54  *
55  * @n
56  *
57  * These seem to be heavily based on https://github.com/LonelyWolf/stm32/blob/master/stm32l-dosfs/RTC.c
58  *
59  ******************************************************************************/
60 
61 
62 #include "rtc.h" /* Include corresponding header file */
63 
64 #include <stdint.h> /* (u)intXX_t */
65 #include "stm32f1xx_ll_bus.h" /* Low-Level Clock Management */
66 #include "stm32f1xx_ll_rcc.h" /* Low-Level Clock Management */
67 #include "stm32f1xx_ll_pwr.h" /* Low-Level Power Management */
68 #include "stm32f1xx_ll_rtc.h" /* Low-Level Real Time Clock Peripheral API */
69 #include "stm32f1xx_ll_exti.h" /* Low-level interrupt functionality */
70 #include "stm32f1xx_ll_cortex.h" /* For LL_SYSTICK_IsActiveCounterFlag() */
71 #include "util.h" /* Utility functionality */
72 
73 
74 /* Local definitions */
75 
76 /** Oscillator time-out values */
77 #define RTC_TIMEOUT_MS ((uint32_t)1000)
78 
79 /** ck_apre = LSEFreq / (ASYNC prediv + 1) = 1Hz with LSEFreq = 32768Hz */
80 #define RTC_ASYNCH_PREDIV ((uint32_t)0x7FFF)
81 
82 
83 /* Local variables */
84 /** Variable used for Timeout management */
85 static uint32_t Timeout = 0;
86 
87 
88 /* Local prototypes */
89 static void RTCcounter_to_dateTime(uint32_t counter);
90 static uint32_t dateTime_to_RTCcounter(void);
91 
92 
93 /**************************************************************************//**
94  * @brief
95  * Function to initialize the Real Time Clock.
96  *****************************************************************************/
97 void RTC_Init(void)
98 {
99  /* Enable the PWR Clock and access to the backup domain */
100  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);
101  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_BKP);
102  LL_PWR_EnableBkUpAccess();
103 
104  /* Enable LSE only if disabled.*/
105  if (LL_RCC_LSE_IsReady() != 1)
106  {
107  LL_RCC_ForceBackupDomainReset();
108  LL_RCC_ReleaseBackupDomainReset();
109  LL_RCC_LSE_Enable();
110 
112 
113  while (LL_RCC_LSE_IsReady() != 1)
114  {
116 
117  if (Timeout == 0) while(1); /* LSE activation error */
118  }
119  }
120 
121  /* Set LSE as the clock source for the RTC if not already the case */
122  if (LL_RCC_GetRTCClockSource() != LL_RCC_RTC_CLKSOURCE_LSE)
123  {
124  LL_RCC_SetRTCClockSource(LL_RCC_RTC_CLKSOURCE_LSE);
125  }
126 
127  /* Enable RTC peripheral Clock */
128  LL_RCC_EnableRTC();
129 
130 
131  /* Disable RTC registers write protection */
132  LL_RTC_DisableWriteProtection(RTC);
133 
134  /* Enter in initialization mode */
135  if (LL_RTC_EnterInitMode(RTC) != 0)
136  {
137  while(1); /* Initialization Error */
138  }
139 
140  /* Configure RTC prescaler, set Asynch Prediv value according to source clock */
141  LL_RTC_SetAsynchPrescaler(RTC, RTC_ASYNCH_PREDIV);
142 
143  /* RTC_Alarm Interrupt Configuration: EXTI configuration */
144  LL_EXTI_EnableIT_0_31(LL_EXTI_LINE_17);
145  LL_EXTI_EnableRisingTrig_0_31(LL_EXTI_LINE_17);
146 
147  /* Configure the NVIC for RTC Alarm */
150 
151  /* Enable Second Interrupt */
152  LL_RTC_EnableIT_SEC(RTC);
153 
154  /* Exit of initialization mode */
155  LL_RTC_ExitInitMode(RTC);
156 
157  /* Enable RTC registers write protection */
158  LL_RTC_EnableWriteProtection(RTC);
159 
160 
161  /* Signal logic so the hour/min/second fields have to be converted to chars after RTC initialization (~boot) */
162  rtc.firstUpdate = 1;
163 }
164 
165 
166 /**************************************************************************//**
167  * @brief
168  * Function to convert the RTC counter value to date-time values in the struct.
169  *
170  * @note
171  * This is a static method because it's only internally used in this file
172  * and called by other methods if necessary.
173  *
174  * @param[in] counter
175  * RTC counter-value (`uint32_t`).
176  *****************************************************************************/
177 static void RTCcounter_to_dateTime(uint32_t counter)
178 {
179  unsigned long time;
180  unsigned long t1, a, b, c, d, e, m;
181  int year = 0;
182  int mon = 0;
183  int wday = 0;
184  int mday = 0;
185  int hour = 0;
186  int min = 0;
187  int sec = 0;
188  uint64_t jd = 0;;
189  uint64_t jdn = 0;
190 
191  jd = ((counter+43200)/(86400>>1)) + (2440587<<1) + 1;
192  jdn = jd>>1;
193 
194  time = counter;
195  t1 = time/60;
196  sec = time - t1*60;
197 
198  time = t1;
199  t1 = time/60;
200  min = time - t1*60;
201 
202  time = t1;
203  t1 = time/24;
204  hour = time - t1*24;
205 
206  wday = jdn%7;
207 
208  a = jdn + 32044;
209  b = (4*a+3)/146097;
210  c = a - (146097*b)/4;
211  d = (4*c+3)/1461;
212  e = c - (1461*d)/4;
213  m = (5*e+2)/153;
214  mday = e - (153*m+2)/5 + 1;
215  mon = m + 3 - 12*(m/10);
216  year = 100*b + d - 4800 + (m/10);
217 
218  if (rtc.latest == 0)
219  {
220  rtc.year1 = year;
221  rtc.month1 = mon;
222  rtc.day1 = mday;
223  rtc.hour1 = hour;
224  rtc.min1 = min;
225  rtc.sec1 = sec;
226  rtc.latest = 1;
227  }
228  else if (rtc.latest == 1)
229  {
230  rtc.year0 = year;
231  rtc.month0 = mon;
232  rtc.day0 = mday;
233  rtc.hour0 = hour;
234  rtc.min0 = min;
235  rtc.sec0 = sec;
236  rtc.latest = 0;
237  }
238 
239  rtc.wday = wday;
240 }
241 
242 
243 /**************************************************************************//**
244  * @brief
245  * Function to convert the date-time values in the struct
246  * to a corresponding RTC counter value.
247  *
248  * @note
249  * This is a static method because it's only internally used in this file
250  * and called by other methods if necessary.
251  *
252  * @return
253  * The corresponding RTC counter value (`uint32_t`)
254  *****************************************************************************/
255 static uint32_t dateTime_to_RTCcounter(void)
256 {
257  uint8_t a;
258  uint16_t y;
259  uint8_t m;
260  uint32_t JDN;
261 
262  if (rtc.latest == 0)
263  {
264  a=(14-rtc.month0)/12;
265  y=rtc.year0+4800-a;
266  m=rtc.month0+(12*a)-3;
267 
268  JDN=rtc.day0;
269  JDN+=(153*m+2)/5;
270  JDN+=365*y;
271  JDN+=y/4;
272  JDN+=-y/100;
273  JDN+=y/400;
274  JDN = JDN -32045;
275  JDN = JDN - JULIAN_DATE_BASE;
276  JDN*=86400;
277  JDN+=(rtc.hour0*3600);
278  JDN+=(rtc.min0*60);
279  JDN+=(rtc.sec0);
280  }
281  else if (rtc.latest == 1)
282  {
283  a=(14-rtc.month1)/12;
284  y=rtc.year1+4800-a;
285  m=rtc.month1+(12*a)-3;
286 
287  JDN=rtc.day1;
288  JDN+=(153*m+2)/5;
289  JDN+=365*y;
290  JDN+=y/4;
291  JDN+=-y/100;
292  JDN+=y/400;
293  JDN = JDN -32045;
294  JDN = JDN - JULIAN_DATE_BASE;
295  JDN*=86400;
296  JDN+=(rtc.hour1*3600);
297  JDN+=(rtc.min1*60);
298  JDN+=(rtc.sec1);
299  }
300 
301  return (JDN);
302 }
303 
304 
305 /**************************************************************************//**
306  * @brief
307  * Function to update the RTC data in the struct.
308  *****************************************************************************/
309 void readFromRTC(void)
310 {
311  RTCcounter_to_dateTime(LL_RTC_TIME_Get(RTC));
312 }
313 
314 
315 /**************************************************************************//**
316  * @brief
317  * Function to update the RTC values according to the data in the struct.
318  *****************************************************************************/
319 void writeToRTC(void)
320 {
321  /* Disable RTC registers write protection */
322  LL_RTC_DisableWriteProtection(RTC);
323 
324  /* Enter in initialization mode */
325  if (LL_RTC_EnterInitMode(RTC) != 0)
326  {
327  while(1); /* Initialization Error */
328  }
329 
330  /* Set time and date according to struct values, which have been converted to onee uint32_t value */
331  LL_RTC_TIME_SetCounter(RTC, dateTime_to_RTCcounter());
332 
333  /* Clear RSF flag */
334  LL_RTC_ClearFlag_RS(RTC);
335 
337 
338  /* Wait until the RTC Time and Date registers (RTC_TR and RTC_DR) are synchronized with RTC APB clock */
339  while(LL_RTC_IsActiveFlag_RS(RTC) != 1)
340  {
342 
343  if (Timeout == 0) while(1); /* Initialization Error */
344  }
345 
346  /* Exit of initialization mode */
347  if (LL_RTC_ExitInitMode(RTC) != 0)
348  {
349  while(1); /* Initialization Error */
350  }
351 
352  /* Enable RTC registers write protection */
353  LL_RTC_EnableWriteProtection(RTC);
354 }
RTC_dateTime_t::hour0
uint8_t hour0
Definition: rtc.h:55
Timeout
static uint32_t Timeout
Definition: rtc.c:85
stm32f1xx_ll_rtc.h
Header file of RTC LL module.
RTC
#define RTC
Definition: stm32f103xb.h:651
RTC_dateTime_t::min1
uint8_t min1
Definition: rtc.h:61
RTC_Init
void RTC_Init(void)
Function to initialize the Real Time Clock.
Definition: rtc.c:97
LL_SYSTICK_IsActiveCounterFlag
__STATIC_INLINE uint32_t LL_SYSTICK_IsActiveCounterFlag(void)
This function checks if the Systick counter flag is active or not.
Definition: stm32f1xx_ll_cortex.h:231
RTC_IRQn
@ RTC_IRQn
Definition: stm32f103xb.h:86
RTC_TIMEOUT_MS
#define RTC_TIMEOUT_MS
Definition: rtc.c:77
rtc
struct RTC_dateTime_t rtc
stm32f1xx_ll_pwr.h
Header file of PWR LL module.
stm32f1xx_ll_cortex.h
Header file of CORTEX LL module.
dateTime_to_RTCcounter
static uint32_t dateTime_to_RTCcounter(void)
Function to convert the date-time values in the struct to a corresponding RTC counter value.
Definition: rtc.c:255
RTCcounter_to_dateTime
static void RTCcounter_to_dateTime(uint32_t counter)
Function to convert the RTC counter value to date-time values in the struct.
Definition: rtc.c:177
RTC_dateTime_t::year0
uint16_t year0
Definition: rtc.h:82
stm32f1xx_ll_bus.h
Header file of BUS LL module.
JULIAN_DATE_BASE
#define JULIAN_DATE_BASE
Definition: rtc.h:47
RTC_dateTime_t::min0
uint8_t min0
Definition: rtc.h:60
LSE_TIMEOUT_VALUE
#define LSE_TIMEOUT_VALUE
Definition: stm32_hal_legacy.h:3300
RTC_dateTime_t::month0
uint8_t month0
Definition: rtc.h:77
writeToRTC
void writeToRTC(void)
Function to update the RTC values according to the data in the struct.
Definition: rtc.c:319
RTC_dateTime_t::year1
uint16_t year1
Definition: rtc.h:83
RTC_dateTime_t::sec1
uint8_t sec1
Definition: rtc.h:66
RTC_dateTime_t::day0
uint8_t day0
Definition: rtc.h:70
RTC_dateTime_t::sec0
uint8_t sec0
Definition: rtc.h:65
RTC_dateTime_t::latest
uint8_t latest
Definition: rtc.h:53
NVIC_SetPriority
#define NVIC_SetPriority
Definition: core_armv8mbl.h:1197
RTC_dateTime_t::day1
uint8_t day1
Definition: rtc.h:71
RTC_dateTime_t::wday
uint8_t wday
Definition: rtc.h:75
NVIC_EnableIRQ
#define NVIC_EnableIRQ
Definition: core_armv8mbl.h:1190
RTC_ASYNCH_PREDIV
#define RTC_ASYNCH_PREDIV
Definition: rtc.c:80
rtc.h
RTC functionality for high-precision logging voltage/current meter.
readFromRTC
void readFromRTC(void)
Function to update the RTC data in the struct.
Definition: rtc.c:309
stm32f1xx_ll_exti.h
Header file of EXTI LL module.
stm32f1xx_ll_rcc.h
Header file of RCC LL module.
RTC_dateTime_t::hour1
uint8_t hour1
Definition: rtc.h:56
util.h
Utility functionality for high-precision logging voltage/current meter.
RTC_dateTime_t::month1
uint8_t month1
Definition: rtc.h:78
RTC_dateTime_t::firstUpdate
uint8_t firstUpdate
Definition: rtc.h:52