Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 16 Jul 2020 12:35:55 -0300
From:      "Dr. Rolf Jansen" <freebsd-rj@obsigna.com>
To:        Ian Lepore <ian@freebsd.org>
Cc:        freebsd-arm@freebsd.org
Subject:   Re: DS3231 on BeagleBone Black with FreeBSD 13-CURRENT exactly 20 h off  backwards
Message-ID:  <BC3C9537-FC1F-436B-A898-265D3D320271@obsigna.com>
In-Reply-To: <99ec5bfbe697e0cbf8b6262783256bffcbf55f55.camel@freebsd.org>
References:  <3BE2A8B4-AD53-4DFE-8C38-D5BB4063CFE9@obsigna.com> <CECBFBC7-6C63-4762-9A55-BE84DA53BBD2@obsigna.com> <99ec5bfbe697e0cbf8b6262783256bffcbf55f55.camel@freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help
> Am 15.07.2020 um 23:32 schrieb Ian Lepore <ian@freebsd.org>:
>=20
> On Wed, 2020-07-15 at 12:15 -0300, Dr. Rolf Jansen wrote:
>>> Am 15.07.2020 um 09:52 schrieb Dr. Rolf Jansen <
>>> freebsd-rj@obsigna.com <mailto:freebsd-rj@obsigna.com>>:
>>>=20
>>> 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.
>>>=20
>>> Looking at the Maxim DS3231 datasheet (
>>> https://datasheets.maximintegrated.com/en/ds/DS3231.pdf#page=3D11 =
<https://datasheets.maximintegrated.com/en/ds/DS3231.pdf#page=3D11>; <
>>> https://datasheets.maximintegrated.com/en/ds/DS3231.pdf#page=3D11 =
<https://datasheets.maximintegrated.com/en/ds/DS3231.pdf#page=3D11>>),
>>> 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.
>>>=20
>>> BTW: the following looks strange:
>>>=20
>>>=20
> =
https://github.com/freebsd/freebsd/blob/b2d136be8c26e5efaf82b7bb25432207a6=
82e250/sys/dev/iicbus/ds3231.c#L526 =
<https://github.com/freebsd/freebsd/blob/b2d136be8c26e5efaf82b7bb25432207a=
682e250/sys/dev/iicbus/ds3231.c#L526>
>>> <
>>> =
https://github.com/freebsd/freebsd/blob/b2d136be8c26e5efaf82b7bb25432207a6=
82e250/sys/dev/iicbus/ds3231.c#L526 =
<https://github.com/freebsd/freebsd/blob/b2d136be8c26e5efaf82b7bb25432207a=
682e250/sys/dev/iicbus/ds3231.c#L526>
>>>>=20
>>>=20
>>> 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
>>=20
>> For the time being I resolved the issue for me, by completely
>> dropping AM/PM support - I don=E2=80=99t need it, and I anyway always =
need to
>> remember that AM means (Am Morgen :-).
>>=20
>> 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 =3D 0x3f.
>>=20
>=20
> The driver originally forced the chip into 24-hour mode.  I'm the one
> who added support for 12 or 24 hour mode, so this is probably my =
fault.
> It seems nicer to me to try to deal with whatever mode the chip is
> already in (in case you're dual-booting into some other OS that wants
> it to be a certain way).  I'm pretty sure I've got one of those chips
> around here somewhere, I'll find some time this weekend to get the
> driver fixed.
>=20
> -- Ian

I appreciate your efforts for AM/PM support, only I am not sufficiently =
familiar with the very details of this format, for example I always got =
wrong the special meanings of 0:00 AM vs. 0:00 PM and 12:00 AM vs. 12:00 =
PM. So, I am the wrong person to bugfix AM/PM issues. I applied the =
temporary dirty fix of dropping out AM/PM only for getting the driver =
quickly working on my side, and I could continue with my current =
project. Once the driver is fixed upstream, I will use that one, of =
course.

That said, I wrote a sysctl function for directly getting/setting the =
time in the RTC with unix time values. Perhaps, something like this =
would facilitate your debugging efforts, and here it comes:

static int
ds3231_unixtime_sysctl(SYSCTL_HANDLER_ARGS)
{
	int c, error;
	struct timespec ts =3D {};
	struct bcd_clocktime bct;
	struct ds3231_softc *sc =3D (struct ds3231_softc *)arg1;
	uint8_t data[7];

	if (req->newptr =3D=3D NULL) { // get the unixtime
		/* If the clock halted, we don't have good data. */
		if ((error =3D ds3231_status_read(sc)) !=3D 0) {
			device_printf(sc->sc_dev, "cannot read from =
RTC.\n");
			return (error);
		}
		if (sc->sc_status & DS3231_STATUS_OSF)
			return (EINVAL);

		error =3D iicdev_readfrom(sc->sc_dev, DS3231_SECS, data, =
sizeof(data),
			IIC_INTRWAIT);
		if (error !=3D 0) {
			device_printf(sc->sc_dev, "cannot read from =
RTC.\n");
			return (error);
		}

		bct.nsec =3D 0;
		bct.sec  =3D data[DS3231_SECS]  & DS3231_SECS_MASK;
		bct.min  =3D data[DS3231_MINS]  & DS3231_MINS_MASK;
		bct.hour =3D data[DS3231_HOUR]  & DS3231_HOUR_MASK_12HR;
		bct.day  =3D data[DS3231_DATE]  & DS3231_DATE_MASK;
		bct.mon  =3D data[DS3231_MONTH] & DS3231_MONTH_MASK;
		bct.year =3D data[DS3231_YEAR]  & DS3231_YEAR_MASK;
		bct.ispm =3D data[DS3231_HOUR]  & DS3231_HOUR_IS_PM;

		/*
		 * If the century flag has toggled since we last saw it, =
there has been
		 * a century rollover.  If this is the first time we're =
seeing it,
		 * remember the state so we can preserve its polarity on =
writes.
		 */
		c =3D (data[DS3231_MONTH] & DS3231_C_MASK) ? 1 : 0;
		if (sc->sc_last_c =3D=3D -1)
			sc->sc_last_c =3D c;
		else if (c !=3D sc->sc_last_c) {
			sc->sc_year0 +=3D 100;
			sc->sc_last_c =3D c;
		}
		bct.year |=3D sc->sc_year0;

		error =3D clock_bcd_to_ts(&bct, &ts, false);
		if (error =3D=3D 0) {
			error =3D sysctl_handle_long(oidp, &ts.tv_sec, =
0, req);
		}
	}

	else if ((error =3D sysctl_handle_long(oidp, &ts.tv_sec, 0, req) =
=3D=3D 0)) { // set the unixtime
		/*
		 * We request a timespec with no resolution-adjustment.  =
That also
		 * disables utc adjustment, so apply that ourselves.
		 */
		ts.tv_sec -=3D utc_offset();
		clock_ts_to_bcd(&ts, &bct, false);

		data[DS3231_SECS]    =3D bct.sec;
		data[DS3231_MINS]    =3D bct.min;
		data[DS3231_HOUR]    =3D bct.hour | 0b01000000;
		data[DS3231_DATE]    =3D bct.day;
		data[DS3231_WEEKDAY] =3D bct.dow + 1;
		data[DS3231_MONTH]   =3D bct.mon;
		data[DS3231_YEAR]    =3D bct.year & 0xff;
		if (sc->sc_last_c)
			data[DS3231_MONTH] |=3D DS3231_C_MASK;

		/* Write the time back to RTC. */
		error =3D iicdev_writeto(sc->sc_dev, DS3231_SECS, data, =
sizeof(data),
			IIC_INTRWAIT);
		if (error !=3D 0) {
			device_printf(sc->sc_dev, "cannot write to =
RTC.\n");
			return (error);
		}

		/*
		 * Unlike most hardware, the osc-was-stopped bit does =
not clear itself
		 * after setting the time, it has to be manually written =
to zero.
		 */
		if (sc->sc_status & DS3231_STATUS_OSF) {
			if ((error =3D ds3231_status_read(sc)) !=3D 0) {
				device_printf(sc->sc_dev, "cannot read =
from RTC.\n");
				return (error);
			}
			sc->sc_status &=3D ~DS3231_STATUS_OSF;
			if ((error =3D ds3231_status_write(sc, 0, 0)) !=3D=
 0) {
				device_printf(sc->sc_dev, "cannot write =
to RTC.\n");
				return (error);
			}
		}
	}

	return (error);
}


...
	/* Date/Time. */
	SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "unixtime",
	    CTLFLAG_RW | CTLTYPE_ULONG | CTLFLAG_MPSAFE, sc, 0,
	    ds3231_unixtime_sysctl, "LU", "get/set the Date/Time =
formatted as a UNIX time stamp");

	/* Temperature. */
...


Then, I wrote a shell script for testing, whether setting/getting the =
time works as expected (checkds3231.sh):

#!/bin/sh

DATE=3D`date "+%Y-%m-%d"`

sysctl dev.ds3231.0.unixtime=3D`date -jf "%Y-%m-%d %H:%M:%S" "+%s" =
$DATE" 00:26:14"` > /dev/null 2>&1
date -jf "%s" "+%Y-%m-%d %H:%M:%S" `sysctl -n dev.ds3231.0.unixtime`

sysctl dev.ds3231.0.unixtime=3D`date -jf "%Y-%m-%d %H:%M:%S" "+%s" =
$DATE" 01:26:14"` > /dev/null 2>&1
date -jf "%s" "+%Y-%m-%d %H:%M:%S" `sysctl -n dev.ds3231.0.unixtime`

sysctl dev.ds3231.0.unixtime=3D`date -jf "%Y-%m-%d %H:%M:%S" "+%s" =
$DATE" 02:26:14"` > /dev/null 2>&1
date -jf "%s" "+%Y-%m-%d %H:%M:%S" `sysctl -n dev.ds3231.0.unixtime`

sysctl dev.ds3231.0.unixtime=3D`date -jf "%Y-%m-%d %H:%M:%S" "+%s" =
$DATE" 03:26:14"` > /dev/null 2>&1
date -jf "%s" "+%Y-%m-%d %H:%M:%S" `sysctl -n dev.ds3231.0.unixtime`

sysctl dev.ds3231.0.unixtime=3D`date -jf "%Y-%m-%d %H:%M:%S" "+%s" =
$DATE" 04:26:14"` > /dev/null 2>&1
date -jf "%s" "+%Y-%m-%d %H:%M:%S" `sysctl -n dev.ds3231.0.unixtime`

sysctl dev.ds3231.0.unixtime=3D`date -jf "%Y-%m-%d %H:%M:%S" "+%s" =
$DATE" 05:26:14"` > /dev/null 2>&1
date -jf "%s" "+%Y-%m-%d %H:%M:%S" `sysctl -n dev.ds3231.0.unixtime`

sysctl dev.ds3231.0.unixtime=3D`date -jf "%Y-%m-%d %H:%M:%S" "+%s" =
$DATE" 06:26:14"` > /dev/null 2>&1
date -jf "%s" "+%Y-%m-%d %H:%M:%S" `sysctl -n dev.ds3231.0.unixtime`

sysctl dev.ds3231.0.unixtime=3D`date -jf "%Y-%m-%d %H:%M:%S" "+%s" =
$DATE" 07:26:14"` > /dev/null 2>&1
date -jf "%s" "+%Y-%m-%d %H:%M:%S" `sysctl -n dev.ds3231.0.unixtime`

sysctl dev.ds3231.0.unixtime=3D`date -jf "%Y-%m-%d %H:%M:%S" "+%s" =
$DATE" 08:26:14"` > /dev/null 2>&1
date -jf "%s" "+%Y-%m-%d %H:%M:%S" `sysctl -n dev.ds3231.0.unixtime`

sysctl dev.ds3231.0.unixtime=3D`date -jf "%Y-%m-%d %H:%M:%S" "+%s" =
$DATE" 09:26:14"` > /dev/null 2>&1
date -jf "%s" "+%Y-%m-%d %H:%M:%S" `sysctl -n dev.ds3231.0.unixtime`

sysctl dev.ds3231.0.unixtime=3D`date -jf "%Y-%m-%d %H:%M:%S" "+%s" =
$DATE" 10:26:14"` > /dev/null 2>&1
date -jf "%s" "+%Y-%m-%d %H:%M:%S" `sysctl -n dev.ds3231.0.unixtime`

sysctl dev.ds3231.0.unixtime=3D`date -jf "%Y-%m-%d %H:%M:%S" "+%s" =
$DATE" 11:26:14"` > /dev/null 2>&1
date -jf "%s" "+%Y-%m-%d %H:%M:%S" `sysctl -n dev.ds3231.0.unixtime`

sysctl dev.ds3231.0.unixtime=3D`date -jf "%Y-%m-%d %H:%M:%S" "+%s" =
$DATE" 12:26:14"` > /dev/null 2>&1
date -jf "%s" "+%Y-%m-%d %H:%M:%S" `sysctl -n dev.ds3231.0.unixtime`

sysctl dev.ds3231.0.unixtime=3D`date -jf "%Y-%m-%d %H:%M:%S" "+%s" =
$DATE" 13:26:14"` > /dev/null 2>&1
date -jf "%s" "+%Y-%m-%d %H:%M:%S" `sysctl -n dev.ds3231.0.unixtime`

sysctl dev.ds3231.0.unixtime=3D`date -jf "%Y-%m-%d %H:%M:%S" "+%s" =
$DATE" 14:26:14"` > /dev/null 2>&1
date -jf "%s" "+%Y-%m-%d %H:%M:%S" `sysctl -n dev.ds3231.0.unixtime`

sysctl dev.ds3231.0.unixtime=3D`date -jf "%Y-%m-%d %H:%M:%S" "+%s" =
$DATE" 15:26:14"` > /dev/null 2>&1
date -jf "%s" "+%Y-%m-%d %H:%M:%S" `sysctl -n dev.ds3231.0.unixtime`

sysctl dev.ds3231.0.unixtime=3D`date -jf "%Y-%m-%d %H:%M:%S" "+%s" =
$DATE" 16:26:14"` > /dev/null 2>&1
date -jf "%s" "+%Y-%m-%d %H:%M:%S" `sysctl -n dev.ds3231.0.unixtime`

sysctl dev.ds3231.0.unixtime=3D`date -jf "%Y-%m-%d %H:%M:%S" "+%s" =
$DATE" 17:26:14"` > /dev/null 2>&1
date -jf "%s" "+%Y-%m-%d %H:%M:%S" `sysctl -n dev.ds3231.0.unixtime`

sysctl dev.ds3231.0.unixtime=3D`date -jf "%Y-%m-%d %H:%M:%S" "+%s" =
$DATE" 18:26:14"` > /dev/null 2>&1
date -jf "%s" "+%Y-%m-%d %H:%M:%S" `sysctl -n dev.ds3231.0.unixtime`

sysctl dev.ds3231.0.unixtime=3D`date -jf "%Y-%m-%d %H:%M:%S" "+%s" =
$DATE" 19:26:14"` > /dev/null 2>&1
date -jf "%s" "+%Y-%m-%d %H:%M:%S" `sysctl -n dev.ds3231.0.unixtime`

sysctl dev.ds3231.0.unixtime=3D`date -jf "%Y-%m-%d %H:%M:%S" "+%s" =
$DATE" 20:26:14"` > /dev/null 2>&1
date -jf "%s" "+%Y-%m-%d %H:%M:%S" `sysctl -n dev.ds3231.0.unixtime`

sysctl dev.ds3231.0.unixtime=3D`date -jf "%Y-%m-%d %H:%M:%S" "+%s" =
$DATE" 21:26:14"` > /dev/null 2>&1
date -jf "%s" "+%Y-%m-%d %H:%M:%S" `sysctl -n dev.ds3231.0.unixtime`

sysctl dev.ds3231.0.unixtime=3D`date -jf "%Y-%m-%d %H:%M:%S" "+%s" =
$DATE" 22:26:14"` > /dev/null 2>&1
date -jf "%s" "+%Y-%m-%d %H:%M:%S" `sysctl -n dev.ds3231.0.unixtime`

sysctl dev.ds3231.0.unixtime=3D`date -jf "%Y-%m-%d %H:%M:%S" "+%s" =
$DATE" 23:26:14"` > /dev/null 2>&1
date -jf "%s" "+%Y-%m-%d %H:%M:%S" `sysctl -n dev.ds3231.0.unixtime`

sysctl dev.ds3231.0.unixtime=3D`date "+%s"` > /dev/null 2>&1
date -jf "%s" "+%Y-%m-%d %H:%M:%S" `sysctl -n dev.ds3231.0.unixtime`

The sample output here looks good:

2020-07-16 00:26:14
2020-07-16 01:26:14
2020-07-16 02:26:14
2020-07-16 03:26:14
2020-07-16 04:26:14
2020-07-16 05:26:14
2020-07-16 06:26:14
2020-07-16 07:26:14
2020-07-16 08:26:14
2020-07-16 09:26:14
2020-07-16 10:26:14
2020-07-16 11:26:14
2020-07-16 12:26:14
2020-07-16 13:26:14
2020-07-16 14:26:14
2020-07-16 15:26:14
2020-07-16 16:26:14
2020-07-16 17:26:14
2020-07-16 18:26:14
2020-07-16 19:26:14
2020-07-16 20:26:14
2020-07-16 21:26:14
2020-07-16 22:26:14
2020-07-16 23:26:14
2020-07-16 12:32:12

Best regards

Rolf=



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?BC3C9537-FC1F-436B-A898-265D3D320271>