DS3231 on BeagleBone Black with FreeBSD 13-CURRENT exactly 20 h off backwards
Dr. Rolf Jansen
freebsd-rj at obsigna.com
Wed Jul 15 15:15:41 UTC 2020
> Am 15.07.2020 um 09:52 schrieb Dr. Rolf Jansen <freebsd-rj at obsigna.com>:
>
> I added a DS3231 module to the i2c2 bus of the BBB running 13-CURRENT. Everything work fine, except that when I set a time in the range of 20:00 to 24:00 UTC, then on starting up the RTC reports a date/time of exactly 20 hours off backwards. While, when I set a time in the range from 0:00 to 19:59 UTC, it would be correctly stored by the RTC.
>
> Looking at the Maxim DS3231 datasheet (https://datasheets.maximintegrated.com/en/ds/DS3231.pdf#page=11 <https://datasheets.maximintegrated.com/en/ds/DS3231.pdf#page=11>), it might be that something gets mixed-up when setting bits 5 and 6 of the hours register. In the history of ds3231.c, I saw that 24 hour mode is not more forced anymore. Perhaps an unresolved ambiguity was introduced by this change.
>
> BTW: the following looks strange:
>
> https://github.com/freebsd/freebsd/blob/b2d136be8c26e5efaf82b7bb25432207a682e250/sys/dev/iicbus/ds3231.c#L526 <https://github.com/freebsd/freebsd/blob/b2d136be8c26e5efaf82b7bb25432207a682e250/sys/dev/iicbus/ds3231.c#L526>
>
> This would add 256 instead of 100 when rolling over the century, really? On real world systems this will let to a Year-2100 problem, better we solve this quickly, since the time is running, and 80 years compares to nothing on the geologic time scale :-D
For the time being I resolved the issue for me, by completely dropping AM/PM support - I don’t need it, and I anyway always need to remember that AM means (Am Morgen :-).
DS3231_HOUR_MASK_24HR is definitely wrong, since this prevents the setting of times above 20 h. Reading said data sheet, I am almost sure, that DS3231_HOUR_MASK_24HR must be the same as DS3231_HOUR_MASK_12HR = 0x3f.
# svn diff https://svn.freebsd.org/base/head/sys/dev/iicbus/ds3231.c ./ds3231.c
Index: ds3231.c
===================================================================
--- ds3231.c (revision 363224)
+++ ds3231.c (working copy)
@@ -62,7 +62,6 @@
uint16_t sc_addr; /* DS3231 slave address. */
uint8_t sc_ctrl;
uint8_t sc_status;
- bool sc_use_ampm;
};
static void ds3231_start(void *);
@@ -142,6 +141,25 @@
}
static int
+ds3231_set_24hrs_mode(struct ds3231_softc *sc)
+{
+ int error;
+ uint8_t hour;
+
+ error = ds3231_read1(sc->sc_dev, DS3231_HOUR, &hour);
+ if (error) {
+ device_printf(sc->sc_dev, "cannot read from RTC.\n");
+ return (error);
+ }
+ hour &= ~DS3231_C_MASK;
+ error = ds3231_write1(sc->sc_dev, DS3231_HOUR, hour);
+ if (error != 0)
+ device_printf(sc->sc_dev, "cannot write to RTC.\n");
+
+ return (error);
+}
+
+static int
ds3231_temp_read(struct ds3231_softc *sc, int *temp)
{
int error, neg, t;
@@ -440,6 +458,10 @@
ds3231_status_write(sc, 1, 1);
ds3231_ctrl_write(sc);
+ /* Set the 24 hours mode. */
+ if (ds3231_set_24hrs_mode(sc) != 0)
+ return;
+
/* Temperature. */
SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "temperature",
CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
@@ -479,7 +501,7 @@
int c, error;
struct bcd_clocktime bct;
struct ds3231_softc *sc;
- uint8_t data[7], hourmask;
+ uint8_t data[7];
sc = device_get_softc(dev);
@@ -498,17 +520,10 @@
return (error);
}
- /* If chip is in AM/PM mode remember that. */
- if (data[DS3231_HOUR] & DS3231_HOUR_USE_AMPM) {
- sc->sc_use_ampm = true;
- hourmask = DS3231_HOUR_MASK_12HR;
- } else
- hourmask = DS3231_HOUR_MASK_24HR;
-
bct.nsec = 0;
bct.sec = data[DS3231_SECS] & DS3231_SECS_MASK;
bct.min = data[DS3231_MINS] & DS3231_MINS_MASK;
- bct.hour = data[DS3231_HOUR] & hourmask;
+ bct.hour = data[DS3231_HOUR] & DS3231_HOUR_MASK_12HR;
bct.day = data[DS3231_DATE] & DS3231_DATE_MASK;
bct.mon = data[DS3231_MONTH] & DS3231_MONTH_MASK;
bct.year = data[DS3231_YEAR] & DS3231_YEAR_MASK;
@@ -523,13 +538,13 @@
if (sc->sc_last_c == -1)
sc->sc_last_c = c;
else if (c != sc->sc_last_c) {
- sc->sc_year0 += 0x100;
+ sc->sc_year0 += 100;
sc->sc_last_c = c;
}
bct.year |= sc->sc_year0;
clock_dbgprint_bcd(sc->sc_dev, CLOCK_DBG_READ, &bct);
- return (clock_bcd_to_ts(&bct, ts, sc->sc_use_ampm));
+ return (clock_bcd_to_ts(&bct, ts, false));
}
static int
@@ -539,7 +554,6 @@
struct bcd_clocktime bct;
struct ds3231_softc *sc;
uint8_t data[7];
- uint8_t pmflags;
sc = device_get_softc(dev);
@@ -548,20 +562,13 @@
* disables utc adjustment, so apply that ourselves.
*/
ts->tv_sec -= utc_offset();
- clock_ts_to_bcd(ts, &bct, sc->sc_use_ampm);
+ clock_ts_to_bcd(ts, &bct, false);
clock_dbgprint_bcd(sc->sc_dev, CLOCK_DBG_WRITE, &bct);
- /* If the chip is in AM/PM mode, adjust hour and set flags as needed. */
- if (sc->sc_use_ampm) {
- pmflags = DS3231_HOUR_USE_AMPM;
- if (bct.ispm)
- pmflags |= DS3231_HOUR_IS_PM;
- } else
- pmflags = 0;
data[DS3231_SECS] = bct.sec;
data[DS3231_MINS] = bct.min;
- data[DS3231_HOUR] = bct.hour | pmflags;
+ data[DS3231_HOUR] = bct.hour | 0b01000000;
data[DS3231_DATE] = bct.day;
data[DS3231_WEEKDAY] = bct.dow + 1;
data[DS3231_MONTH] = bct.mon;
More information about the freebsd-arm
mailing list