14 // Place RTC on 32kHz xtal and disconnect power.
16 static inline void rtcSleep (void)
18 RTC_CCR = (RTC_CCR_CLKEN | RTC_CCR_CLKSRC);
19 SCB_PCONP &= ~SCB_PCONP_PCRTC;
23 // Prepare clock for interactive use.
25 static inline void rtcWake (void)
27 RTC_CCR = (RTC_CCR_CLKEN | RTC_CCR_CLKSRC);
28 SCB_PCONP |= SCB_PCONP_PCRTC;
32 // Read clock registers and return tm structure.
34 static void rtcRead (struct tm *theTime, unsigned int *milliseconds)
36 unsigned int ticks32Khz;
42 portENTER_CRITICAL ();
46 ctime0.i = RTC_CTIME0;
47 ctime1.i = RTC_CTIME1;
48 ctime2.i = RTC_CTIME2;
51 ticks32Khz = (RTC_CTC & 0xfffe);
52 while (ticks32Khz != (RTC_CTC & 0xfffe));
54 while (ctime0.i != RTC_CTIME0);
60 *milliseconds = (((ticks32Khz / 2) * 1000u) / 32768u);
62 theTime->tm_sec = ctime0.seconds;
63 theTime->tm_min = ctime0.minutes;
64 theTime->tm_hour = ctime0.hours;
65 theTime->tm_mday = ctime1.dom;
66 theTime->tm_mon = ctime1.month - 1;
67 theTime->tm_year = ctime1.year - 1900;
68 theTime->tm_wday = ctime0.dow;
69 theTime->tm_yday = ctime2.doy - 1;
70 theTime->tm_isdst = 0;
74 // Set clock to new values.
76 static void rtcWrite (struct tm *newTime)
79 portENTER_CRITICAL ();
81 RTC_CCR &= ~RTC_CCR_CLKEN;
82 RTC_CCR |= RTC_CCR_CTCRST;
84 RTC_SEC = newTime->tm_sec;
85 RTC_MIN = newTime->tm_min;
86 RTC_HOUR = newTime->tm_hour;
87 RTC_DOM = newTime->tm_mday;
88 RTC_MONTH = newTime->tm_mon + 1;
89 RTC_YEAR = newTime->tm_year + 1900;
90 RTC_DOW = newTime->tm_wday;
91 RTC_DOY = newTime->tm_yday + 1;
93 RTC_CCR &= ~RTC_CCR_CTCRST;
94 RTC_CCR |= RTC_CCR_CLKEN;
103 time_t rtcGetEpochSeconds (unsigned int *milliseconds)
107 rtcRead (&tm, milliseconds);
111 void rtcSetEpochSeconds (time_t now)
115 localtime_r (&now, &tm);
120 // Start clock so that the sytsem may use it.
122 static void rtcInitClockCalendar (void)
131 ctime0.i = RTC_CTIME0;
132 ctime1.i = RTC_CTIME1;
133 ctime2.i = RTC_CTIME2;
136 // Leisurely tear the packed time apart into individual time.
138 if ((ctime0.seconds < 0) || (ctime0.seconds > 59)) nonsense = 1;
139 if ((ctime0.minutes < 0) || (ctime0.minutes > 59)) nonsense = 1;
140 if ((ctime0.hours < 0) || (ctime0.hours > 23)) nonsense = 1;
141 if ((ctime1.dom < 1) || (ctime1.dom > 31)) nonsense = 1;
142 if ((ctime1.month < 1) || (ctime1.month > 12)) nonsense = 1;
143 if ((ctime1.year < 1980) || (ctime1.year > 2050)) nonsense = 1;
144 if ((ctime0.dow < 0) || (ctime0.dow > 6)) nonsense = 1;
145 if ((ctime2.doy < 0) || (ctime2.doy > 366)) nonsense = 1;
150 // Set the clock to Jan 1, 2006 00:00:00
153 rtcSetEpochSeconds ((time_t) 1136073600);
163 SCB_PCONP |= SCB_PCONP_PCRTC;
167 RTC_CCR |= RTC_CCR_CLKSRC;
169 RTC_AMR = RTC_AMR_AMRMASK;
172 RTC_ILR = RTC_ILR_MASK;
174 RTC_CCR |= RTC_CCR_CLKEN;
176 VIC_IntSelect &= ~VIC_IntSelect_RTC;
177 #ifdef RTC_NONVECTOREDIRQ
178 VIC_DefVectAddr = (portLONG) rtcISR;
180 VIC_VectAddr6 = (portLONG) rtcISR;
181 VIC_VectCntl6 = VIC_VectCntl_ENABLE | VIC_Channel_RTC;
183 VIC_IntEnable = VIC_IntEnable_RTC;
185 rtcInitClockCalendar ();
188 int rtcSetAlarm (struct tm *tm)
190 if (tm && (mktime (tm) < time (NULL)))
195 RTC_AMR = RTC_AMR_AMRMASK;
199 RTC_ALYEAR = tm->tm_year + 1900;
200 RTC_ALMON = tm->tm_mon + 1;
201 RTC_ALDOM = tm->tm_mday;
202 RTC_ALHOUR = tm->tm_hour;
203 RTC_ALMIN = tm->tm_min;
204 RTC_ALSEC = tm->tm_sec;
208 RTC_AMR = RTC_AMR_AMRDOW | RTC_AMR_AMRDOY;
216 struct tm *rtcGetAlarmTm (struct tm *tm)
220 memset (tm, 0, sizeof (* tm));
224 if (RTC_AMR != RTC_AMR_AMRMASK)
226 tm->tm_year = RTC_ALYEAR - 1900;
227 tm->tm_mon = RTC_ALMON - 1;
228 tm->tm_mday = RTC_ALDOM;
229 tm->tm_hour = RTC_ALHOUR;
230 tm->tm_min = RTC_ALMIN;
231 tm->tm_sec = RTC_ALSEC;
236 memcpy (tm, localtime (&now), sizeof (* tm));
245 time_t rtcGetAlarmEpochSeconds (void)
249 return mktime (rtcGetAlarmTm (&tm));
252 int rtcPeriodicAlarm (int mode)
258 state = RTC_CIIR & RTC_CIIR_IMMIN;
261 RTC_CIIR &= ~RTC_CIIR_IMMIN;
263 RTC_CIIR |= RTC_CIIR_IMMIN;
267 return state ? 1 : 0;