ARMEBS4  revision-26.06.2015
time_rtc.c
1 /**
2  * \brief <sys/time.h> functions implementation
3  * Please use functions from <time.h> to access the rtc.
4  */
5 
6 #include <time.h>
7 #include <sys/time.h>
8 #include <reent.h>
9 #include <errno.h>
10 
11 #include "stm32/stm32f4xx_pwr.h"
12 #include "stm32/stm32f4xx_rcc.h"
13 #include "stm32/stm32f4xx_rtc.h"
14 #include "heivs/error.h"
15 
16 #define _SEC_IN_MINUTE 60L
17 #define _SEC_IN_HOUR 3600L
18 #define _SEC_IN_DAY 86400L
19 #define YEAR_BASE 1900
20 
21 static const int _DAYS_BEFORE_MONTH[12] =
22 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
23 
24 #define _ISLEAP(y) (((y) % 4) == 0 && (((y) % 100) != 0 || (((y)+1900) % 400) == 0))
25 #define _DAYS_IN_YEAR(year) (_ISLEAP(year) ? 366 : 365)
26 
27 static time_t timegm(struct tm *tim_p)
28 {
29  time_t tim = 0;
30  long days = 0;
31  int year, isdst=0;
32 
33  /* compute hours, minutes, seconds */
34  tim += tim_p->tm_sec + (tim_p->tm_min * _SEC_IN_MINUTE) +
35  (tim_p->tm_hour * _SEC_IN_HOUR);
36 
37  /* compute days in year */
38  days += tim_p->tm_mday - 1;
39  days += _DAYS_BEFORE_MONTH[tim_p->tm_mon];
40  if (tim_p->tm_mon > 1 && _DAYS_IN_YEAR (tim_p->tm_year) == 366)
41  days++;
42 
43  /* compute day of the year */
44  tim_p->tm_yday = days;
45 
46  if (tim_p->tm_year > 10000 || tim_p->tm_year < -10000)
47  return (time_t) -1;
48 
49  /* compute days in other years */
50  if ((year = tim_p->tm_year) > 70)
51  {
52  for (year = 70; year < tim_p->tm_year; year++)
53  days += _DAYS_IN_YEAR (year);
54  }
55  else if (year < 70)
56  {
57  for (year = 69; year > tim_p->tm_year; year--)
58  days -= _DAYS_IN_YEAR (year);
59  days -= _DAYS_IN_YEAR (year);
60  }
61 
62  /* compute total seconds */
63  tim += (days * _SEC_IN_DAY);
64 
65  /* reset isdst flag to what we have calculated */
66  tim_p->tm_isdst = isdst;
67 
68  /* compute day of the week */
69  if ((tim_p->tm_wday = (days + 4) % 7) < 0)
70  tim_p->tm_wday += 7;
71 
72  return tim;
73 }
74 
75 int _gettimeofday_r(struct _reent *ptr, struct timeval *tv, void *tz)
76 {
77  struct tm tm;
78  status_e status;
79  RTC_TimeTypeDef time;
80  RTC_DateTypeDef date;
81  uint32_t subsecond;
82  uint32_t prediv_s;
83 
84  (void)tz;
85 
86  // Read in this order is safe
87  subsecond = RTC->SSR;
88  RTC_GetTime(RTC_Format_BIN,&time);
89  RTC_GetDate(RTC_Format_BIN,&date);
90 
91  status = NO_ERROR;
92  if (status != NO_ERROR)
93  {
94  ptr->_errno = -EFAULT;
95  return -1;
96  }
97 
98  tm.tm_hour = time.RTC_Hours;
99  tm.tm_min = time.RTC_Minutes;
100  tm.tm_sec = time.RTC_Seconds;
101  tm.tm_mon = date.RTC_Month - 1;
102  tm.tm_mday = date.RTC_Date;
103  tm.tm_year = 100 + date.RTC_Year;
104 
105  /* Ignored by mktime */
106  tm.tm_wday = 0;
107  tm.tm_yday = 0;
108 
109  tv->tv_sec = timegm(&tm);
110 
111  prediv_s = (RTC->PRER & RTC_PRER_PREDIV_S);
112  tv->tv_usec = 1000000*(prediv_s - subsecond)/(prediv_s + 1);
113 
114  return 0;
115 }
116 
117 /**
118  * \brief Initialize the RTC and set the date and time
119  *
120  * \param theTime the time
121  * \param theDate the date
122  */
123 static void RTC_Set(RTC_TimeTypeDef * theTime, RTC_DateTypeDef * theDate)
124 {
125  ErrorStatus stm32_status;
126 
127  PWR_BackupAccessCmd(ENABLE);
128  RCC_LSEConfig(RCC_LSE_ON); // turn ON 32.768 kHz oscillator
129  RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); // set RTC clock is LSE clock
130  RCC_RTCCLKCmd(ENABLE); // optional ?
131 
132  RTC_WriteProtectionCmd(DISABLE);
133  do
134  {
135  stm32_status = RTC_EnterInitMode();
136  } while (stm32_status == ERROR);
137 
138  stm32_status = RTC_SetTime(RTC_Format_BIN,theTime);
139  stm32_status = RTC_SetDate(RTC_Format_BIN,theDate);
140 
141  RTC_ExitInitMode();
142  RTC_WriteProtectionCmd(ENABLE);
143  PWR_BackupAccessCmd(DISABLE);
144 }
145 
146 int settimeofday(const struct timeval *tv, const struct timezone *tz)
147 {
148  RTC_TimeTypeDef time;
149  RTC_DateTypeDef date;
150 
151  struct tm tm;
152 
153  (void)tz;
154  gmtime_r(&tv->tv_sec, &tm);
155 
156  time.RTC_Hours = tm.tm_hour;
157  time.RTC_Minutes = tm.tm_min;
158  time.RTC_Seconds = tm.tm_sec;
159  date.RTC_Month = tm.tm_mon + 1;
160  date.RTC_Date = tm.tm_mday;
161  date.RTC_Year = tm.tm_year % 100;
162  date.RTC_WeekDay = (tm.tm_wday == 0) ? 7 : tm.tm_wday;
163 
164  RTC_Set(&time, &date);
165 
166  return 0;
167 }
168 
169 /* Europe/Zurich */
170 static __tzinfo_type tzinfo =
171 {
172  1, 0,
173  {
174  {'M', 3, 5, 0, 7200, (time_t)0, -3600 }, //CET, March, Last week, Sunday, 2:00 o´clock, -1 hour to UTC
175  {'M', 10, 5, 0, 10800, (time_t)0, -7200 } //CET, October, Last week, Sunday, 3:00 o´clock, -2 hours to UTC
176  }
177 };
178 
179 __tzinfo_type *__gettzinfo(void)
180 {
181  return &tzinfo;
182 }
This file contains all the functions prototypes for the RCC firmware library.
simple time abstraction
This file contains all the functions prototypes for the RTC firmware library.
This file contains all the functions prototypes for the PWR firmware library.
Errors definitions.
RTC Date structure definition.
Definition: stm32f4xx_rtc.h:82
uint8_t RTC_WeekDay
Definition: stm32f4xx_rtc.h:84
uint8_t RTC_Seconds
Definition: stm32f4xx_rtc.h:72
RTC Time structure definition.
Definition: stm32f4xx_rtc.h:62
uint8_t RTC_Minutes
Definition: stm32f4xx_rtc.h:69
status_e
Known errors.
Definition: error.h:21
No error.
Definition: error.h:28