1 /*
2 * Copyright (c) 2019-2020 Peter Bigot Consulting, LLC
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stdio.h>
8
9 #include <zephyr/kernel.h>
10 #include <zephyr/device.h>
11 #include <zephyr/drivers/counter.h>
12 #include <zephyr/sys/printk.h>
13 #include <zephyr/drivers/rtc/maxim_ds3231.h>
14
15 /* Format times as: YYYY-MM-DD HH:MM:SS DOW DOY */
format_time(time_t time,long nsec)16 static const char *format_time(time_t time,
17 long nsec)
18 {
19 static char buf[64];
20 char *bp = buf;
21 char *const bpe = bp + sizeof(buf);
22 struct tm tv;
23 struct tm *tp = gmtime_r(&time, &tv);
24
25 bp += strftime(bp, bpe - bp, "%Y-%m-%d %H:%M:%S", tp);
26 if (nsec >= 0) {
27 bp += snprintf(bp, bpe - bp, ".%09lu", nsec);
28 }
29 bp += strftime(bp, bpe - bp, " %a %j", tp);
30 return buf;
31 }
32
sec_counter_callback(const struct device * dev,uint8_t id,uint32_t ticks,void * ud)33 static void sec_counter_callback(const struct device *dev,
34 uint8_t id,
35 uint32_t ticks,
36 void *ud)
37 {
38 printk("Counter callback at %u ms, id %d, ticks %u, ud %p\n",
39 k_uptime_get_32(), id, ticks, ud);
40 }
41
sec_alarm_handler(const struct device * dev,uint8_t id,uint32_t syncclock,void * ud)42 static void sec_alarm_handler(const struct device *dev,
43 uint8_t id,
44 uint32_t syncclock,
45 void *ud)
46 {
47 uint32_t now = maxim_ds3231_read_syncclock(dev);
48 struct counter_alarm_cfg alarm = {
49 .callback = sec_counter_callback,
50 .ticks = 10,
51 .user_data = ud,
52 };
53
54 printk("setting channel alarm\n");
55 int rc = counter_set_channel_alarm(dev, id, &alarm);
56
57 printk("Sec signaled at %u ms, param %p, delay %u; set %d\n",
58 k_uptime_get_32(), ud, now - syncclock, rc);
59 }
60
61
62 /** Calculate the normalized result of a - b.
63 *
64 * For both inputs and outputs tv_nsec must be in the range [0,
65 * NSEC_PER_SEC). tv_sec may be negative, zero, or positive.
66 */
timespec_subtract(struct timespec * amb,const struct timespec * a,const struct timespec * b)67 void timespec_subtract(struct timespec *amb,
68 const struct timespec *a,
69 const struct timespec *b)
70 {
71 if (a->tv_nsec >= b->tv_nsec) {
72 amb->tv_nsec = a->tv_nsec - b->tv_nsec;
73 amb->tv_sec = a->tv_sec - b->tv_sec;
74 } else {
75 amb->tv_nsec = NSEC_PER_SEC + a->tv_nsec - b->tv_nsec;
76 amb->tv_sec = a->tv_sec - b->tv_sec - 1;
77 }
78 }
79
80 /** Calculate the normalized result of a + b.
81 *
82 * For both inputs and outputs tv_nsec must be in the range [0,
83 * NSEC_PER_SEC). tv_sec may be negative, zero, or positive.
84 */
timespec_add(struct timespec * apb,const struct timespec * a,const struct timespec * b)85 void timespec_add(struct timespec *apb,
86 const struct timespec *a,
87 const struct timespec *b)
88 {
89 apb->tv_nsec = a->tv_nsec + b->tv_nsec;
90 apb->tv_sec = a->tv_sec + b->tv_sec;
91 if (apb->tv_nsec >= NSEC_PER_SEC) {
92 apb->tv_sec += 1;
93 apb->tv_nsec -= NSEC_PER_SEC;
94 }
95 }
96
min_alarm_handler(const struct device * dev,uint8_t id,uint32_t syncclock,void * ud)97 static void min_alarm_handler(const struct device *dev,
98 uint8_t id,
99 uint32_t syncclock,
100 void *ud)
101 {
102 uint32_t time = 0;
103 struct maxim_ds3231_syncpoint sp = { 0 };
104
105 (void)counter_get_value(dev, &time);
106
107 uint32_t uptime = k_uptime_get_32();
108 uint16_t ms = uptime % 1000U;
109
110 uptime /= 1000U;
111 uint8_t se = uptime % 60U;
112
113 uptime /= 60U;
114 uint8_t mn = uptime % 60U;
115
116 uptime /= 60U;
117 uint8_t hr = uptime;
118
119 (void)maxim_ds3231_get_syncpoint(dev, &sp);
120
121 uint32_t offset_syncclock = syncclock - sp.syncclock;
122 uint32_t offset_s = time - (uint32_t)sp.rtc.tv_sec;
123 uint32_t syncclock_Hz = maxim_ds3231_syncclock_frequency(dev);
124 struct timespec adj;
125
126 adj.tv_sec = offset_syncclock / syncclock_Hz;
127 adj.tv_nsec = (offset_syncclock % syncclock_Hz)
128 * (uint64_t)NSEC_PER_SEC / syncclock_Hz;
129
130 int32_t err_ppm = (int32_t)(offset_syncclock
131 - offset_s * syncclock_Hz)
132 * (int64_t)1000000
133 / (int32_t)syncclock_Hz / (int32_t)offset_s;
134 struct timespec *ts = &sp.rtc;
135
136 ts->tv_sec += adj.tv_sec;
137 ts->tv_nsec += adj.tv_nsec;
138 if (ts->tv_nsec >= NSEC_PER_SEC) {
139 ts->tv_sec += 1;
140 ts->tv_nsec -= NSEC_PER_SEC;
141 }
142
143 printk("%s: adj %d.%09lu, uptime %u:%02u:%02u.%03u, clk err %d ppm\n",
144 format_time(time, -1),
145 (uint32_t)(ts->tv_sec - time), ts->tv_nsec,
146 hr, mn, se, ms, err_ppm);
147 }
148
149 struct maxim_ds3231_alarm sec_alarm;
150 struct maxim_ds3231_alarm min_alarm;
151
show_counter(const struct device * ds3231)152 static void show_counter(const struct device *ds3231)
153 {
154 uint32_t now = 0;
155
156 printk("\nCounter at %p\n", ds3231);
157 printk("\tMax top value: %u (%08x)\n",
158 counter_get_max_top_value(ds3231),
159 counter_get_max_top_value(ds3231));
160 printk("\t%u channels\n", counter_get_num_of_channels(ds3231));
161 printk("\t%u Hz\n", counter_get_frequency(ds3231));
162
163 printk("Top counter value: %u (%08x)\n",
164 counter_get_top_value(ds3231),
165 counter_get_top_value(ds3231));
166
167 (void)counter_get_value(ds3231, &now);
168
169 printk("Now %u: %s\n", now, format_time(now, -1));
170 }
171
172 /* Take the currently stored RTC time and round it up to the next
173 * hour. Program the RTC as though this time had occurred at the
174 * moment the application booted.
175 *
176 * Subsequent reads of the RTC time adjusted based on a syncpoint
177 * should match the uptime relative to the programmed hour.
178 */
set_aligned_clock(const struct device * ds3231)179 static void set_aligned_clock(const struct device *ds3231)
180 {
181 if (!IS_ENABLED(CONFIG_APP_SET_ALIGNED_CLOCK)) {
182 return;
183 }
184
185 uint32_t syncclock_Hz = maxim_ds3231_syncclock_frequency(ds3231);
186 uint32_t syncclock = maxim_ds3231_read_syncclock(ds3231);
187 uint32_t now = 0;
188 int rc = counter_get_value(ds3231, &now);
189 uint32_t align_hour = now + 3600 - (now % 3600);
190
191 struct maxim_ds3231_syncpoint sp = {
192 .rtc = {
193 .tv_sec = align_hour,
194 .tv_nsec = (uint64_t)NSEC_PER_SEC * syncclock / syncclock_Hz,
195 },
196 .syncclock = syncclock,
197 };
198
199 struct k_poll_signal ss;
200 struct sys_notify notify;
201 struct k_poll_event sevt = K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL,
202 K_POLL_MODE_NOTIFY_ONLY,
203 &ss);
204
205 k_poll_signal_init(&ss);
206 sys_notify_init_signal(¬ify, &ss);
207
208 uint32_t t0 = k_uptime_get_32();
209
210 rc = maxim_ds3231_set(ds3231, &sp, ¬ify);
211
212 printk("\nSet %s at %u ms past: %d\n", format_time(sp.rtc.tv_sec, sp.rtc.tv_nsec),
213 syncclock, rc);
214
215 /* Wait for the set to complete */
216 rc = k_poll(&sevt, 1, K_FOREVER);
217
218 uint32_t t1 = k_uptime_get_32();
219
220 /* Delay so log messages from sync can complete */
221 k_sleep(K_MSEC(100));
222 printk("Synchronize final: %d %d in %u ms\n", rc, ss.result, t1 - t0);
223
224 rc = maxim_ds3231_get_syncpoint(ds3231, &sp);
225 printk("wrote sync %d: %u %u at %u\n", rc,
226 (uint32_t)sp.rtc.tv_sec, (uint32_t)sp.rtc.tv_nsec,
227 sp.syncclock);
228 }
229
main(void)230 int main(void)
231 {
232 const struct device *const ds3231 = DEVICE_DT_GET_ONE(maxim_ds3231);
233
234 if (!device_is_ready(ds3231)) {
235 printk("%s: device not ready.\n", ds3231->name);
236 return 0;
237 }
238
239 uint32_t syncclock_Hz = maxim_ds3231_syncclock_frequency(ds3231);
240
241 printk("DS3231 on %s syncclock %u Hz\n\n", CONFIG_BOARD, syncclock_Hz);
242
243 int rc = maxim_ds3231_stat_update(ds3231, 0, MAXIM_DS3231_REG_STAT_OSF);
244
245 if (rc >= 0) {
246 printk("DS3231 has%s experienced an oscillator fault\n",
247 (rc & MAXIM_DS3231_REG_STAT_OSF) ? "" : " not");
248 } else {
249 printk("DS3231 stat fetch failed: %d\n", rc);
250 return 0;
251 }
252
253 /* Show the DS3231 counter properties */
254 show_counter(ds3231);
255
256 /* Show the DS3231 ctrl and ctrl_stat register values */
257 printk("\nDS3231 ctrl %02x ; ctrl_stat %02x\n",
258 maxim_ds3231_ctrl_update(ds3231, 0, 0),
259 maxim_ds3231_stat_update(ds3231, 0, 0));
260
261 /* Test maxim_ds3231_set, if enabled */
262 set_aligned_clock(ds3231);
263
264 struct k_poll_signal ss;
265 struct sys_notify notify;
266 struct maxim_ds3231_syncpoint sp = { 0 };
267 struct k_poll_event sevt = K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL,
268 K_POLL_MODE_NOTIFY_ONLY,
269 &ss);
270
271 k_poll_signal_init(&ss);
272 sys_notify_init_signal(¬ify, &ss);
273
274 uint32_t t0 = k_uptime_get_32();
275
276 rc = maxim_ds3231_synchronize(ds3231, ¬ify);
277 printk("\nSynchronize init: %d\n", rc);
278
279 rc = k_poll(&sevt, 1, K_FOREVER);
280
281 uint32_t t1 = k_uptime_get_32();
282
283 k_sleep(K_MSEC(100)); /* wait for log messages */
284
285 printk("Synchronize complete in %u ms: %d %d\n", t1 - t0, rc, ss.result);
286
287 rc = maxim_ds3231_get_syncpoint(ds3231, &sp);
288 printk("\nread sync %d: %u %u at %u\n", rc,
289 (uint32_t)sp.rtc.tv_sec, (uint32_t)sp.rtc.tv_nsec,
290 sp.syncclock);
291
292 rc = maxim_ds3231_get_alarm(ds3231, 0, &sec_alarm);
293 printk("\nAlarm 1 flags %x at %u: %d\n", sec_alarm.flags,
294 (uint32_t)sec_alarm.time, rc);
295 rc = maxim_ds3231_get_alarm(ds3231, 1, &min_alarm);
296 printk("Alarm 2 flags %x at %u: %d\n", min_alarm.flags,
297 (uint32_t)min_alarm.time, rc);
298
299 /* One-shot auto-disable callback in 5 s. The handler will
300 * then use the base device counter API to schedule a second
301 * alarm 10 s later.
302 */
303 sec_alarm.time = sp.rtc.tv_sec + 5;
304 sec_alarm.flags = MAXIM_DS3231_ALARM_FLAGS_AUTODISABLE
305 | MAXIM_DS3231_ALARM_FLAGS_DOW;
306 sec_alarm.handler = sec_alarm_handler;
307 sec_alarm.user_data = &sec_alarm;
308
309 printk("Min Sec base time: %s\n", format_time(sec_alarm.time, -1));
310
311 /* Repeating callback at rollover to a new minute. */
312 min_alarm.time = sec_alarm.time;
313 min_alarm.flags = 0
314 | MAXIM_DS3231_ALARM_FLAGS_IGNDA
315 | MAXIM_DS3231_ALARM_FLAGS_IGNHR
316 | MAXIM_DS3231_ALARM_FLAGS_IGNMN
317 | MAXIM_DS3231_ALARM_FLAGS_IGNSE;
318 min_alarm.handler = min_alarm_handler;
319
320 rc = maxim_ds3231_set_alarm(ds3231, 0, &sec_alarm);
321 printk("Set sec alarm %x at %u ~ %s: %d\n", sec_alarm.flags,
322 (uint32_t)sec_alarm.time, format_time(sec_alarm.time, -1), rc);
323
324 rc = maxim_ds3231_set_alarm(ds3231, 1, &min_alarm);
325 printk("Set min alarm flags %x at %u ~ %s: %d\n", min_alarm.flags,
326 (uint32_t)min_alarm.time, format_time(min_alarm.time, -1), rc);
327
328 printk("%u ms in: get alarms: %d %d\n", k_uptime_get_32(),
329 maxim_ds3231_get_alarm(ds3231, 0, &sec_alarm),
330 maxim_ds3231_get_alarm(ds3231, 1, &min_alarm));
331 if (rc >= 0) {
332 printk("Sec alarm flags %x at %u ~ %s\n", sec_alarm.flags,
333 (uint32_t)sec_alarm.time, format_time(sec_alarm.time, -1));
334
335 printk("Min alarm flags %x at %u ~ %s\n", min_alarm.flags,
336 (uint32_t)min_alarm.time, format_time(min_alarm.time, -1));
337 }
338
339 k_sleep(K_FOREVER);
340 return 0;
341 }
342