Homepage Wiki Forum Buy

RTC DS1307

From GNUBLIN

severity (level) requirement Gnublin family
Gnublin logo advanced.png Kernel compile, Toolchain All

Contents


In order to remember the time in a Linux system although the system was without power you need a real time clock which is buffered by a battery.

MODULE-RTC SCHRAEGBILD 002.jpg

There is a very small command to set the time of the rtc-module

gnublin-rtc -s "2013/01/20 11:23:12"

If you want to read out the rtc you can do this with the following command:

gnublin-rtc -g

Now if you want to set your system date after the rtc's date you can do this with the following command:

gnublin-rtc -x

Controlling a rtc can be so simple.

For Beginners

This section discribes how to connect an RTC IC (here DS1307 or MCP79410 or RV-3029) correctly and ro configure Linux so that the RTC is reachablehwclock.

Note:Without GNUBLIN distribution you should use the adapted I²C-Driver of the Gnublin-Forum! With an original driver an MCP79410 didn't react.

RTC via RV3029

In the actual version of gnublin_defconfig and the GNUBLIN Distribution the driver is already build in.

The driver is located in the menu config under "Device Drivers -> Real Time Clock -> Micro Crystal RV-3029".

After the activation of the driver, the compilation of the modules and the zImage and you get it on the SD-Card you have to do the following steps.

At first you have to load the module (if the driver isn't configured as build in):

modeprobe rtc-rv3029

After that a new I2C-Device has to be build with this command and connected with the driver:

echo rv3029 0x56 > /sys/bus/i2c/devices/i2c-1/new_device

Now it is possible to read the time:

hwclock -r

For further debug outputs add -D to the command.

If you get this error:

RTC_RD_TIME: Inappropriate ioctl for device
ioctl() to /dev/rtc to read the time failed.

read the paragraph #Problem Solving inaporopiate ioctl().

To set the time on the RTC type this command:

hwclock --set --date "2012/11/12 11:11:11"

For further debug messages type here also -D.

After that you can set the system time to the RTC time with this command:

hwclock --hctosys

Setting the System Clock during boot process

If you want to set the system time by default to the RTC time during the start process there for some changes in the system are necessary. At first add to the file /etc/rc.local before exit 0:

echo mcp7940 0x6f > /sys/bus/i2c/devices/i2c-1/new_device
echo "Now setting the date and time."
hwclock --hctosys

After that you add an entry to the file /etc/modules:

rtc-mcp7940

At last the hwclock shellscript has to be deactivated because it involves some complications.

update-rc.d hwclock remove && update-rc.d hwclock.sh remove

Now the bord should set the RTC time as system time by every start.

RTC via MCP7940

In the actual version of gnublin_defconfig and the GNUBLIN Distribution the driver is already build in.

The driver is located in the menu config under "Device Drivers -> Real Time Clock -> Microchip 7940 (MCP7940)".

After the activation of the driver, the compilation of the modules and the zImage and you get it on the SD-Card you have to do the following steps.

At first you have to load the module (if the driver isn't configured as build in):

modprobe rtc-mcp7940

After that a new I2C-Device has to be build with this command and connected with the driver:

echo mcp7940 0x6f > /sys/bus/i2c/devices/i2c-1/new_device

Now it is possible to read the time:

hwclock -r

For further debug outputs add -D to the command.

If you get this error:

Cannot access the Hardware Clock via any known method. Use the --debug option to see the details of our search for an access method. root@gnublin:~# hwclock -r -D hwclock from util-linux-ng 2.17.2 hwclock: Open of /dev/rtc failed, errno=6: No such device or address. No usable clock interface found. Cannot access the Hardware Clock via any known method.

read the paragraph #Problem Solving inaporopiate ioctl().

To set the time on the RTC type this command:

hwclock --set --date "2012/11/12 11:11:11"

For further debug messages type here also -D.

After that you can set the system time to the RTC time with this command:

hwclock --hctosys

Setting the System Clock during boot process

If you want to set the system time by default to the RTC time during the start process there for some changes in the system are necessary. At first add to the file /etc/rc.local before exit 0:

echo mcp7940 0x6f > /sys/bus/i2c/devices/i2c-1/new_device
echo "Now setting the date and time."
hwclock --hctosys

After that you add an entry to the file /etc/modules:

rtc-mcp7940

At last the hwclock shellscript has to be deactivated because it involves some complications.

update-rc.d hwclock remove && update-rc.d hwclock.sh remove

Now the bord should set the RTC time as system time by every start.

For Advanced Users

RTC with DS1307

This site describes how to upgrade your Gnublin with a RTC. I'ts also explained how to configure your Linux system on the GNUBLIN to use the RTC via "hwclock".

Schematic

Schematic DS1307
Legend Value Description
R1 1.2k i2c Pull-Up SCL to 3.3V
R2 1.2k i2c Pull-Up SDA to 3.3V
C2 100nF compenasting capacitor
X1 32.768 Hz RTC Quarz
B1 (optional) 3V coin cell Battery for the RTC

NOTE: The DS1307 RTC works with 5V and needs a proper supply to work. The I2C ports of GNUBLIN are working with 3,3V but this is no problem if you connect the I2C pullup resistors to the 3,3V supply.


Kernel Configuration

The following kernel options must be activated to make the DS1307 work as a RTC:

Device Drivers:

  • Realtime Clock (RTC_CLASS)
    • /sys/class/rtc/rtcN (sysfs) (RTC_INTF_SYSFS) optional
    • /proc/driver/rtc (procfs for rtc0) (RTC_INTF_PROC) optional
    • /dev/rtcN (character devices) (RTC_INTF_DEV)
    • Dallas/Maxim DS1307/37/38/39/40, ST M41T00, EPSON RX-8025 (RTC_DRV_DS1307)

I have compiled everything as module, but it should also work if you compile it as static module.


Linux modification

This part took most of the time because of the weird I2C interface.

The module rtc_ds1307 only recognizes the RTC if the chip is registered correctly in the I2C-bus. That means:

1. Tell the bus the correct address and type of the device

root@gnublin:/# echo ds1307 0x68 > /sys/bus/i2c/devices/i2c-1/new_device

2. load the module

root@gnublin:/# modprobe rtc_ds1307 2>/dev/null 1>&2

3. creating device-file

root@gnublin:/# mknod /dev/rtc0 c 253 0 2>/dev/null 1>&2


The output of dmesg should look like this:

root@gnublin:/# dmesg
[ 6152.980000] device: 'rtc0': device_add [ 6152.980000] PM: Adding info for No Bus:rtc0 [ 6152.990000] rtc-ds1307 1-0068: rtc core: registered ds1307 as rtc0 [ 6153.000000] rtc-ds1307 1-0068: 56 bytes nvram [ 6153.000000] driver: '1-0068': driver_bound: bound to device 'rtc-ds1307' [ 6153.000000] bus: 'i2c': really_probe: bound device 1-0068 to driver rtc-ds1307

And the output of lsmod like this:

root@gnublin:/# lsmod
Module Size Used by rtc_ds1307 6464 0 rtc_core 11339 1 rtc_ds1307 pegasus 16772 0 mii 3416 1 pegasus

After this the RTC should be configured correctly

To configure the RTC each time the board is starting up i added following lines to the file /etc/init.d/hwclock.sh :

case "$1" in
       start)
#this are the new lines
               if [ ! -d /sys/bus/i2c/devices/1-0068/ ]
               then
                       echo ds1307 0x68 > /sys/bus/i2c/devices/i2c-1/new_device
               fi
               modprobe rtc_ds1307 2>/dev/null 1>&2
               mknod /dev/rtc0 c 253 0 2>/dev/null 1>&2
#end of the new lines
               if [ "$VERBOSE" != no ]

==RTC via MCP79410

An other method is to use a MCP79410 based RTC. Compared to DS1307 the chip works with 3,3V and can so be used without pull-up-resistors.

It's possible to get ready assembled modules from German webshops (e.g. PmodRTCC von Digilent which is easily to connected to the GNUBLIN with the added wires.

Kernel Configuration

To control the MCP7941x its possible to use the driver for the DS1307. There for the same allocations have to be done like mentioned above:

Device Drivers:

  • Realtime Clock (RTC_CLASS)
    • /sys/class/rtc/rtcN (sysfs) (RTC_INTF_SYSFS) optional
    • /proc/driver/rtc (procfs for rtc0) (RTC_INTF_PROC) optional
    • /dev/rtcN (character devices) (RTC_INTF_DEV)
    • Dallas/Maxim DS1307/37/38/39/40, ST M41T00, EPSON RX-8025 (RTC_DRV_DS1307)

Driver Patch

In the Kernel version 2.6.33 the driver supports the DS1307 but the MCP7941x chip family not. There is a Patch, which doesn’t match 100% for GNUBLIN. The aproched patch for the GNUBLIN-Kernel is this:

--- a/drivers/rtc/rtc-ds1307.c	2012-08-31 07:51:50.000000000 +0200
+++ b/drivers/rtc/rtc-ds1307.c	2012-10-11 21:43:42.512435945 +0200
@@ -34,6 +34,7 @@
 	ds_1388,
 	ds_3231,
 	m41t00,
+	mcp7941x,
 	rx_8025,
 	// rs5c372 too?  different address...
 };
@@ -43,6 +44,7 @@
 #define DS1307_REG_SECS		0x00	/* 00-59 */
 #	define DS1307_BIT_CH		0x80
 #	define DS1340_BIT_nEOSC		0x80
+#	define MCP7941X_BIT_ST          0x80
 #define DS1307_REG_MIN		0x01	/* 00-59 */
 #define DS1307_REG_HOUR		0x02	/* 00-23, or 1-12{am,pm} */
 #	define DS1307_BIT_12HR		0x40	/* in REG_HOUR */
@@ -54,6 +56,7 @@
 #define DS1307_REG_MONTH	0x05	/* 01-12 */
 #	define DS1337_BIT_CENTURY	0x80	/* in REG_MONTH */
 #define DS1307_REG_YEAR		0x06	/* 00-99 */
+#      define MCP7941X_BIT_VBATEN      0x08
 
 /* Other registers (control, status, alarms, trickle charge, NVRAM, etc)
  * start at 7, and they differ a LOT. Only control and status matter for
@@ -137,6 +140,8 @@
 },
 [m41t00] = {
 },
+[mcp7941x] = {
+},
 [rx_8025] = {
 }, };
 
@@ -149,6 +154,7 @@
 	{ "ds1340", ds_1340 },
 	{ "ds3231", ds_3231 },
 	{ "m41t00", m41t00 },
+	{ "mcp7941x", mcp7941x },
 	{ "rx8025", rx_8025 },
 	{ }
 };
@@ -364,6 +370,10 @@
 		buf[DS1307_REG_HOUR] |= DS1340_BIT_CENTURY_EN
 				| DS1340_BIT_CENTURY;
 		break;
+	case mcp7941x:
+		buf[DS1307_REG_SECS] |= MCP7941X_BIT_ST;
+		buf[DS1307_REG_WDAY] |= MCP7941X_BIT_VBATEN;
+		break;
 	default:
 		break;
 	}
@@ -829,6 +839,22 @@
 			dev_warn(&client->dev, "SET TIME!\n");
 		}
 		break;
+	case mcp7941x:
+		/* make sure that the backup battery is enabled */
+		if (!(ds1307->regs[DS1307_REG_WDAY] & MCP7941X_BIT_VBATEN)) {
+			i2c_smbus_write_byte_data(client, DS1307_REG_WDAY,
+				ds1307->regs[DS1307_REG_WDAY]
+				| MCP7941X_BIT_VBATEN);
+		}
+
+		/* clock halted?  turn it on, so clock can tick. */
+		if (!(tmp & MCP7941X_BIT_ST)) {
+			i2c_smbus_write_byte_data(client, DS1307_REG_SECS,
+				MCP7941X_BIT_ST);
+			dev_warn(&client->dev, "SET TIME!\n");
+			goto read_rtc;
+		}
+		break;
 	case rx_8025:
 	case ds_1337:
 	case ds_1339:


The code has to be copied in a text editor and saved as file ( e. g. rtc-ds1307_support_MCP7941x.patch) in the main directory of the kernel-sources. After that it's possible to execute the file:

user@home:/home/user/kernel# patch -p1 < rtc-ds1307_support_MCP7941x.patch

Following the kernel has to be compiled and (together with the modules) copied to the SD-Card. Further informations you can find here.

Linux modifications

Now its nearly the same procedure as withe the DS1307. There are only two differences:

  • the chip has to be registered as mcp7941x (not ds1307) on the I²C bus
  • the I²C-address has to match with the address of the datasheet of your module. Here the address is 0x6f (not 0x68

Register the module:

root@gnublin:~# echo mcp7941x 0x6f > /sys/bus/i2c/devices/i2c-1/new_device

Now the driver can be loaded like described above:

root@gnublin:~# modprobe rtc_ds1307

and if its mention the device-file has to be created

root@gnublin:~# mknod /dev/rtc0 c 253 0

Now the clock is assessable with hwclock. In order to set the clock by every boot procedure the file /etc/initd./hwclock.shhas to be modified:

case "$1" in
        start)
#this is nearly new
    		if [ ! -d /sys/bus/i2c/devices/1-006f/ ]; then
			 echo mcp7941x 0x6f > /sys/bus/i2c/devices/i2c-1/new_device
		fi
		modprobe rtc_ds1307 2>/dev/null 1>&2
		if [ ! -c /dev/rtc0 ]; then
			mknod /dev/rtc0 c 253 0 2>/dev/null 1>&2
		fi
#until here
                if [ "$VERBOSE" != no ]

Problem Solving inaporopiate ioctl()

If there is an error message by the hwclock request which includes ioctl() inappropiate ... there is an error with the device file /dev/rtc0. To solve this problem following steps are necessary.

Check if the device file exists:

ls -l /dev | grep rtc

You should get /dev/rtc0 or /dev/rtc as output. If you get /dev/rtc back you have to delete this device file because hwclock will use this file as default but our RTC is only reachabel by /dev/rtc0. To delete the device file type this command:

rm /dev/rtc

Now check if the Major-Number of the RTC match with the device file. There for type this command:

cat /proc/devices | grep rtc

You get back the Major-Number and rtc. Now we chack the Major-Number of /dev/rtc0 by using this command:

ls -l /dev | grep rtc

You find the Major-Number behind the username and user-group. If this number matches with the number of the cat command everything is ok. If not it's necessary to delete the device file and to get a now one with the right number.

rm /dev/rtc0
mknod /dev/rtc0 c <MAJOR> 0

Replace MAJOR with the number you get with "cat /proc/devices | grep rtc". After that hwclock should read and write to the RTC.

Problem Solving RTC_READ_TIME invalid argument

If you get this error message by reading/writing the time

RTC_RD_TIME: Invalid argument
ioctl() to /dev/rtc0 to read the time failed.

you have to use just use this command:

hwclock --systohc -D --noadjfile --utc

Adjusting the Time manualy

If you don't have a RTC yet but you need the time in your Linux system (e.g. to change the password of an user) use this command:

date 072407032012

If you now type

date

you can see the new time.

In other languages