Raspberry PIで、Cライブラリ「WiringPi」を用いて、リアルタイムクロック(RTC)モジュール「RTC-8564NB」を動作させました。西暦(二桁)・月・日・曜・時・分・秒の設定と読み出す時計機能と、32.768kHz,1024Hz, 32Hz, 1HzのCMOS出力が可能で、2番ピンから出力するクロック出力機能を実装しました。なお、RTC-8564NBとRaspberry PIの接続図は、「Raspberry PIへリアルタイムクロックモジュールのI2C接続 」に示します。また、RTC-8564NBのアラーム機能とタイマー機能は「RTC-8564NBによるタイマー作成 」に示します。

WiringPiのインストール

WiringPiを使用するには、I2CライブラリとWiringPi本体をインストールする必要があります。

次のコマンドでI2Cライブラリをインストールします。

# sudo apt-get install libi2c-dev

WiringPi本体はソースコードをgit経由で次のコマンドにより取得します。

# git clone git://git.drogon.net/wiringPi

ダウンロードが完了すると、カレントディレクトリにwiringPiディレクトリができるので、次のコマンドでビルドします。

# cd wiringPi
# ./build

RTC-8564NBプログラム作成

RTC-8564NBが持つ機能のうち、時計機能とクロック出力機能を実装します。これらの機能は,RTC-8564NBに内蔵されているレジスタを設定することにより実現可能です。このRTC-8564NBはI2Cで制御するので、Cライブラリ「WiringPi」を用いて、I2Cを制御します。

プログラムのソースコード「rtc.c」を次に示します。setDateTime関数で時計を設定し、getDateTime関数で時計を読み出します。setClkoutFrequency関数は、クロック出力端子「CLKOUT」2ピンにデータを出力し、1秒ごとに点灯/消灯を繰り返すように設定します。

rtc.c

#include <stdio.h>

#include <wiringPi.h>
#include <wiringPiI2C.h>

// I2C Address
#define RTCS8564_I2C_ADDRESS      0x51

// Registers
#define RTC8564_CONTROL1           0x00
#define RTC8564_CONTROL2           0x01
#define RTC8564_SECONDS            0x02
#define RTC8564_MINUTES            0x03
#define RTC8564_HOURS              0x04
#define RTC8564_DAYS               0x05
#define RTC8564_WEEKDAYS           0x06
#define RTC8564_MONTH_CENTURY      0x07
#define RTC8564_YEARS              0x08
#define RTC8564_MINUTE_ALARM       0x09
#define RTC8564_HOUR_ALARM         0x0a
#define RTC8564_DAY_ALARM          0x0b
#define RTC8564_WEEKDAY_ALARM      0x0c
#define RTC8564_CLKOUT_FREQUENCY   0x0d
#define RTC8564_TIMER_CONTROL      0x0e
#define RTC8564_TIMER              0x0f

// Control1 register
#define RTC8564_STOP_BIT           0x20

// Control2 register
#define RTC8564_TIE_BIT            0x01
#define RTC8564_AIE_BIT            0x02
#define RTC8564_TF_BIT             0x04
#define RTC8564_AF_BIT             0x08
#define RTC8564_TITP_BIT           0x10

// Calendar registers
#define RTCS8564_CAL_VL            0x80
#define RTCS8564_CAL_CENTURY       0x80

// Alarm register
#define RTC8564_AE_NONE            0x00
#define RTC8564_AE_MINUTE          0x01
#define RTC8564_AE_HOUR            0x02
#define RTC8564_AE_DAY             0x04
#define RTC8564_AE_WEEKDAY         0x08
#define RTC8564_AE_ALL             (RTC8564_AE_MINUTE | RTC8564_AE_HOUR | RTC8564_AE_DAY | RTC8564_AE_WEEKDAY)
#define RTC8564_AE_BIT             0x80

// Timer control register
#define RTC8564_CLK_244US          0x00
#define RTC8564_CLK_15MS           0x01
#define RTC8564_CLK_1SEC           0x02
#define RTC8564_CLK_1MIN           0x03
#define RTC8564_TE_BIT             0x80

// Clkout frequency register
#define RTC8564_CLKOUT_32768HZ     0x00
#define RTC8564_CLKOUT_1024HZ      0x01
#define RTC8564_CLKOUT_32HZ        0x02
#define RTC8564_CLKOUT_1HZ         0x03
#define RTCS8564_FE_BIT            0x80

// date and time
struct dateTime {
  char second;             // 0-59
  char minute;             // 0-59
  char hour;               // 0-23
  char day;                // 1-31
  char month;              // 1-12
  char year;               // 00-199
  char weekday;            // 0(Sun)-6(Sat)
};

// alarm
struct alarmTime {
  char minute;             // 0-59
  char hour;               // 0-23
  char day;                // 1-31
  char weekday;            // 0(Sun)-6(Sat)
};

static int dev;

static int init_dev(void)
{
  if ((dev = wiringPiI2CSetup(RTCS8564_I2C_ADDRESS)) == -1)
  {
     return 1 ;
  }
    return 0;
}
void setRegisters(char address, int numData, char *data) {
  char adr;
  int i;
	
  adr = address;
  for (i = 0; i < numData; i++) {
  	wiringPiI2CWriteReg8 (dev, adr, *data);
  	adr ++;
  	data ++;
  }
}

void getRegisters(char address, int numData, char *data) {
  char adr;
  int i;
	
  adr = address;
  for (i = 0; i < numData; i++) {
  	*data = wiringPiI2CReadReg8 (dev, adr);
  	adr ++;
  	data ++;
  }
}

int decimalToBCD(int decimal) {
  return (((decimal / 10) << 4) | (decimal % 10));
}

int BCDToDecimal(int bcd) {
  return ((bcd >> 4) * 10 + (bcd & 0x0f));
}

void setDateTime(struct dateTime *dt) {
  char data[7];
  
  data[0] = RTC8564_STOP_BIT;
  setRegisters(RTC8564_CONTROL1, 1, data);
  
  data[0] = decimalToBCD(dt->second);
  data[1] = decimalToBCD(dt->minute);
  data[2] = decimalToBCD(dt->hour);
  data[3] = decimalToBCD(dt->day);
  data[4] = decimalToBCD(dt->weekday);
  data[5] = decimalToBCD(dt->month);
  if (dt->year > 100) {
    data[6] = decimalToBCD(dt->year - 100);
    data[5] |= RTCS8564_CAL_CENTURY;
  } else {
    data[6] = decimalToBCD(dt->year);
  }
  setRegisters(RTC8564_SECONDS, 7, data);

  data[0] = 0x00;
  setRegisters(RTC8564_CONTROL1, 1, data);
}

int getDateTime(struct dateTime *dt) {
  char data[7];
  
  getRegisters(RTC8564_SECONDS, 7, data);
  
  if (data[0] & RTCS8564_CAL_VL) {
    return -1;
  }
  
  dt->second  = BCDToDecimal(data[0] & 0x7f);
  dt->minute  = BCDToDecimal(data[1] & 0x7f);
  dt->hour    = BCDToDecimal(data[2] & 0x3f);
  dt->day     = BCDToDecimal(data[3] & 0x3f);
  dt->weekday = BCDToDecimal(data[4] & 0x07);
  dt->month   = BCDToDecimal(data[5] & 0x1f);
  dt->year    = BCDToDecimal(data[6]);
  
  if (data[5] & RTCS8564_CAL_CENTURY) {
    dt->year += 100;
  }
  return 0; 
}

void setClkoutFrequency(char frequency) {
  
  frequency |= RTCS8564_FE_BIT;
  setRegisters(RTC8564_CLKOUT_FREQUENCY, 1, &frequency); 
}

int main(int argc, char **argv) {
  struct dateTime dt = {0, 0, 0, 1, 1, 13, 2};  // 2013 January 1st, Tue 00:00:50
  struct dateTime get_dt;
  int count ;
	
  if(init_dev()==1)  return 1;
    
  setDateTime(&dt);
  count = 5;
  while(count--){
    getDateTime(&get_dt);
    printf("second:%d minute:%d hour:%d\n",get_dt.second,get_dt.minute, get_dt.hour);
	sleep(5);	
  }
	
  setClkoutFrequency( RTC8564_CLKOUT_1HZ);    // Setup CLKOUT frequency.

  return 0;
}

コンパイル・リンクは次のコマンドで実行します。

# gcc -o rtc rtc.c -lwiringPi

出来上がったプログラムを次のコマンドで実行します。

# sudo ./rtc

次のように結果が表示され、LEDが1秒ごとに点灯/消灯を繰り返します。

# ./rtc
second:0 minute:0 hour:0
second:5 minute:0 hour:0
second:10 minute:0 hour:0
second:15 minute:0 hour:0
second:20 minute:0 hour:0

RTC-8564NBのプログラムは最初は「C library for Broadcom BCM 2835 as used in Raspberry Pi 」を使用して作成し、実際に動作させてみましたが、次の点が分からなくて断念し、違うRaspberry PI用のC言語ライブラリ「WiringPi」を使用して作成しました。

  1. 書き込みするレジスタの設定、読み出すレジスタの設定など、レジスタのアドレスの設定方法がわからない。
  2. 一つのAPIで複数のデータが指定できるように、バッファサイズが指定されているが、これは同じレジスタに対して繰り返してreadもしくはWriteするのかが分からない。