Timed bootup of the Rasp Pi with a real-time clock
Continuous Operation
Achieving continuous operation requires a bit more work to allow automation of activities otherwise performed manually. For this purpose, you need to deactivate the entry blacklisti2c-bcm2708
in file /etc/modprobe.d/raspi-blacklist.conf
. Then, you either edit the /etc/modprobe.d/raspi.conf
file and add the line options i2c-bcm2708baudrate=400000
or add the line i2c-dev
in the /etc/modules
file.
You can clean up the startup scripts with the following commands:
sudo update-rc.d fake-hwclock remove
and
sudo update-rc.d hwclock remove
Then, in the directory /etc/init.d
, apply the patch from Listing 5 by adding the following command to the relevant script:
$ patch < hwclock.sh.patch
Listing 5
hwclock.sh.patch
--- hwclock.sh.original 2012-12-22 06:57:47.000000000 +0100 +++ hwclock.sh 2013-11-03 19:27:50.653988109 +0100 @@ -21,10 +21,10 @@ ### BEGIN INIT INFO # Provides: hwclock -# Required-Start: mountdevsubfs +# Required-Start: kmod # Required-Stop: $local_fs # Default-Start: S -# X-Start-Before: checkroot +# X-Start-Before: # Default-Stop: 0 6 ### END INIT INFO @@ -33,6 +33,7 @@ HWCLOCKACCESS=yes HWCLOCKPARS= HCTOSYS_DEVICE=rtc0 +I2CBUS=0 # You only want to use the system timezone or you'll get # potential inconsistency at startup. @@ -43,6 +44,7 @@ [ ! -x /sbin/hwclock ] && return 0 [ ! -r /etc/default/rcS ] || . /etc/default/rcS [ ! -r /etc/default/hwclock ] || . /etc/default/hwclock + [ ! -r /etc/default/rtc ] || . /etc/default/rtc . /lib/lsb/init-functions verbose_log_action_msg() { [ "$VERBOSE" = no ] || log_action_msg "$@"; } @@ -61,8 +63,8 @@ printf "0.0 0 0.0\n0\nUTC" > /etc/adjtime fi - if [ -d /run/udev ] || [ -d /dev/.udev ]; then - return 0 + if [ ! -c /dev/HCTOSYS_DEVICE ]; then + echo mcp7941x 0x6f > /sys/bus/i2c/devices/i2c-$I2CBUS/new_device fi if [ "$HWCLOCKACCESS" != no ]; then
You also should add the new start script from Listing 6. Both start scripts read the number of the I2C bus from the file in Listing 7.
Listing 6
New Start Script
#!/bin/sh ### BEGIN INIT INFO # Provides: raspi-rtc-power # Required-Start: kmod # Required-Stop: halt # X-Stop-After: networking # Default-Start: S # Default-Stop: 0 # Short-Description: on/off Raspi-RTC-Power # Description: switching on/off power via RTC chip on Rasp Pi extension board ### END INIT INFO set -e . /lib/lsb/init-functions ALARM=0; I2CBUS=0; if [ -r /etc/default/rtc ]; then . /etc/default/rtc fi if [ -r /etc/wakealarm ]; then ALARM=$(cat /etc/wakealarm) fi case "${1:-}" in start) log_action_begin_msg "Switching on RasPi-RTC-Power " modprobe i2c-dev i2cset -f -y $I2CBUS 0x6f 0x07 0x00 ES=$? log_action_end_msg $ES ;; stop) log_action_begin_msg "Switching off RasPi-RTC-Power " /sbin/rtc-power $I2CBUS $ALARM ES=$? log_action_end_msg $ES ;; *) echo "Usage: ${0:-} {start|stop}" >&2 exit 1 ;; esac
Listing 7
Number of I2C Bus
# Default settings for Raspi-RTC-Power. This file is # sourced by /bin/sh from /etc/init.d/raspi-rtc-power. # Number of I2C bus hosting the RTC chip: 0 or 1 I2CBUS=<bus#>
Next, incorporate the two updated bootup scripts by typing:
$ sudo update-rc.d hwclock defaults $ sudo update-rc.d raspi-rtc-power defaults
Some necessary functions are not available in the current driver for the MCP79410, so the chip needs its own program (Listing 8) that defines the wake-up time and sets the control register in case of a system shutdown [5] [6].
Listing 8
Program for MCP79410 Chip
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <linux/i2c-dev.h> #include <time.h> #define MCP7941X 0x6f #define CTRLREG 0x07 #define ALARM0REG 0x0a #define ALARMREGSETLEN 6 #define ALARMMC 0x70 #define RTCOUT1 0x80 #define ALARM0EN 0x10 #define MINTIMEGAP 120 char int2bcd(char val) { return (val%10+16*(val/10)); } int main(int argc, char *argv[]) { int file; int i2cbus; // I2C bus number char i2cdevicename[11]; char cbuffer[2]; // I2C Control Buffer char buffer[ALARMREGSETLEN+1]; // I2C Alarm0 Buffer char *end; time_t atime; // Alarm time in seconds since epoch time_t now = time(NULL); struct tm *alarm; // Alarm in broken down time /* get command line parameters */ if (argc != 3) { printf("Error: 2 Parameters expected.\n"); exit(1); } i2cbus = strtol(argv[1], &end, 0); if (*end || i2cbus < 0 || i2cbus > 1) { printf("Error: I2C Bus Number 0 or 1 expected.\n"); exit(2); } atime = strtol(argv[2], &end, 0); if (*end || atime < 0) { printf("Error: Alarm time zero or greater expected.\n"); exit(3); } /* set RTC control and ALARM0 accordingly */ if (atime == 0) { // in case alarm time is zero then ... int i; cbuffer[1] = RTCOUT1; // ... simply switch off ... for (i=1; i<=ALARMREGSETLEN; i++) buffer[i]=0; // ... and clear alarm time } else { // in case of a non-zero alarm time .... cbuffer[1] = ALARM0EN; // ... enable the alarm ... if (atime - now < MINTIMEGAP) atime = now + MINTIMEGAP; // ... make alarm causal ... alarm = gmtime(&atime); if (alarm->tm_sec > 59) alarm->tm_sec = 59; // ... skip any leap seconds if any ... buffer[1] = int2bcd(alarm->tm_sec); // and write seconds buffer[2] = int2bcd(alarm->tm_min); // minutes buffer[3] = int2bcd(alarm->tm_hour); // hour buffer[4] = int2bcd(alarm->tm_wday+1); // day of week buffer[4] |= ALARMMC; // add alarm match condition and write buffer[5] = int2bcd(alarm->tm_mday); // day of month buffer[6] = int2bcd(alarm->tm_mon+1); // month } /* open i2c device */ snprintf(i2cdevicename, 11, "/dev/i2c-%d", i2cbus); file = open(i2cdevicename, O_WRONLY); if (file < 0) { printf("Error: Can't open /dev/i2c-%d.\n", i2cbus); exit(4); } if (ioctl(file, I2C_SLAVE_FORCE, MCP7941X) < 0) { printf("Error: Can't attach I2C Client 0x%x.\n", MCP7941X); exit(5); } /* write alarm0 to RTC */ buffer[0] = ALARM0REG; // set ALARM0 register address if (write(file, buffer, ALARMREGSETLEN+1) != ALARMREGSETLEN+1) { printf("Error: Can't write alarm to I2C Client 0x%x.\n", MCP7941X); exit(6); } /* activate alarm and deactivate power rail */ cbuffer[0] = CTRLREG; // set RTC control register address if (write(file, cbuffer, 2) != 2) { printf("Error: Can't write configuration to I2C Client 0x%x.\n", MCP7941X); exit(7); } exit(0); }
If you set the wake-up time to 0
, the chip will not wake up the Rasp Pi. Instead, a wake-up only occurs with a manual start-up or if the power is turned back on. However, if the wake-up time is set for at least 120 seconds in the future, this will be the chosen wake-up time. Otherwise it will be exactly 120 seconds from the current time.
You should save Listing 8 in the rtc-power.c
file and immediately compile it on the Rasp Pi itself with the gcc rtc-power.c -o rtc-power
command. Before you move the compiled rtc-power
file to the /sbin/
directory, you should set the owner and the group to the appropriate values with sudo chown root:root rtc-power
.
Wake-Up Call
When a system shutdown occurs – initiated, for example, most easily via sudo halt
– the script from Listing 6 expects the wake-up time in the file /etc/wakealarm
to be the number of seconds that have elapsed since January 1, 1970, at 00:00:00 UTC [7].
Listing 9 shows how you can define an absolute wake-up time for Christmas Eve or one that is relative to the current time through the command line (here 7 hours, 11 minutes, 13 seconds in the future).
Listing 9
Define Wake-Up Time
$ sudo sh -c 'date -d "2014-12-24 17:59:30" +%s > /etc/wakealarm' $ sudo sh -c 'echo $((`date +%s` + (7 * 60 + 11) * 60 + 13)) > /etc/wakealarm'
You can deactivate the alarm by deleting this file or by setting the wake-up time to 0
.
« Previous 1 2 3 Next »
Buy this article as PDF
Pages: 8
(incl. VAT)