Das Listing 8 speichern Sie in der Datei rtc-power.c und übersetzen diese mit gcc rtc-power.c -o rtc-power gleich am RasPi selbst. Bevor Sie rtc-power ins Verzeichnis /sbin/ verschieben, setzen Sie noch den Eigentümer und die Gruppe mit sudo chown root:root rtc-power auf die passenden Werte.
Listing 8
#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);
}
Weckruf
Beim Systemstopp – am einfachsten initiiert mit sudo halt – erwartet das Skript aus Listing 6 die Weckzeit in der Datei /etc/wakealarm als Anzahl der Sekunden seit dem 1. Januar 1970 um 00:00:00 UTC [6]. Listing 9 zeigt, wie Sie eine absolute Weckzeit am Weihnachtsabend oder eine relative von der Kommandozeile aus anlegen.
Listing 9
$ 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'
Das Wecken deaktivieren Sie durch das Löschen dieser Datei oder indem Sie die Weckzeit auf 0 setzen.
Fazit
Die hier vorgestellte Hardware mit der zugehörigen Software eignet sich als Basis für eigene Weiterentwicklungen. Vorab ein wenig Übung mit dem Lötkolben sowie eine Elektronikbastlerausstattung in der Werkstatt sind sicher anzuraten, denn den MCP79410 gibt es nur als SMD. Ein Steckbrett wäre eine Alternative, wenn Sie das SMD auf eine eigene steckbare Platine ziehen.
Das Design der Software fällt deutlich eleganter aus, wenn Sie direkt an die Wurzel gehen, also an den Kernel und seine Module. Dort liegen die notwendigen Funktionen zum Ansteuern einer Stromversorgung vor, und auch das Erstellen eines vollwertigen Treibers für den MCP79410 wäre keine Hexerei. Wegen der deutlich effektiveren Kommunikation zwischen Kernel und Hardware ließe sich die Verzögerungszeit des Zeitgebers auf diesem Weg deutlich reduzieren.
Glossar
- RTC
-
Real Time Clock. Chip mit integriertem Quartzoszillator, inkrementiert so in einem bestimmten Intervall einen Zähler. Durch Umrechnen erzeugt der Computer daraus eine für Menschen lesbare Uhrzeit mit Datumsangabe.
- SMD
-
Surface-mounted Device. Oberflächenmontiertes Gerät, dass heutzutage in der Regel mit Maschinen auf die vorbereiteten Leiterbahnen angebracht wird.
Infos
- RTC MCP79410: http://www.microchip.com/pagehandler/en-us/technology/realtimeclock/products.html
- I2C-Wiki: https://i2c.wiki.kernel.org
- NE555 als Zeitgeber: http://de.wikipedia.org/wiki/NE555#Monostabile_Kippstufe
- Raspbian “Wheezy”: http://www.raspberrypi.org/downloads
- Umgang mit I2C, Zeit und Uhrenchips: http://ttp://www.lm-sensors.org/wiki/I2CTools und http://sourceforge.net/projects/nvram-wakeup/
- Unix-Zeit: http://de.wikipedia.org/wiki/Unix-Zeit





