I’ve really been buckling down and trying to get lots of time in on I2C today.
Once being able to communicate with Arduino from my Raspberry Pi using Free Pascal, I wanted to try to read a real time clock using FP as well.
I purchased a Tiny RTC on ebay, I believe. One like this:
First chore was to figure out exactly what I had. I found this explanation of the Tiny RTC:
http://www.hobbyist.co.nz/?q=real_time_clock
Not only is it an RTC, but it has some EEPROM on board as well as a temperature sensor.
First, to connect the RTC to the RPI, I used these instructions from Adafruit:
http://learn.adafruit.com/adding-a-real-time-clock-to-raspberry-pi/overview
No real trick, just connect GND, SCL, SDA as you would expect. Connect the VCC of the RTC to the 5V power supply on the RPI. When first testing the RTC, I connected it directly to the RPI as described above. However, once I saw it was running, I moved the RTC to the 5V side of the logic-level converter with the arduino just to be safe:
Once the RTC was connected, I did an i2cdetect to verify the RPI could see the RTC. It could. I then followed Adafruit’s instructions to set up the RTC as the RPI’s hardware clock. This allowed me to make sure the RTC’s time was valid. A quick summary of the commands necessary:
sudo su modprobe rtc-ds1307 echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device hwclock -r hwclock -w
Once the hwclock is correct, you can set the system clock from it using
hwclock -s
By the way, if you accidentally set the system clock incorrectly, you can force it back using NTP with the following commands:
sudo service ntp stop sudo ntpd -gq sudo service ntp start
Once I knew the RTC was working fine, I was ready to try and read the date/time using Free Pascal. This is really pretty straight forward. 1st I needed a procedure to convert BCD to decimal:
function bcd2dec(bcd: integer): integer; begin bcd2dec := (bcd div 16 * 10) + (bcd mod 16); end;
then you write a zero to the RTC (I believe this indicates you are going to read from the zero register):
buf[0] := 0; fpwrite(handle, buf, 1);
wait about 10ms, then read 7 bytes from the RTC
fpread(handle, buf, 7);
then you just format each byte in the buffer. Here are the seconds:
writeln('sec : ', bcd2dec(buf[0] AND $7F));
One very important note: when using hwclock -w to set the RTC clock, it is going to set it to GMT, not your local time.
Here is the full source of my test program:
program testr2c; {$mode objfpc}{$H+} uses baseUnix, classes, {$IFDEF UNIX}{$IFDEF UseCThreads} cthreads, {$ENDIF}{$ENDIF} sysutils; const I2C_SLAVE = 1795; var buf : packed array [0..9] of byte; devPath : string = '/dev/i2c-1'; handle : Cint; iDevAddr : Cint = $68; function bcd2dec( bcd : integer) : integer; begin bcd2dec := (bcd div 16 * 10) + (bcd mod 16); end; // bcd2dec begin try handle := fpopen(devPath,O_RDWR); fpIOCtl(handle, I2C_SLAVE, pointer(iDevAddr)); except writeln('Error initalizing i2c'); halt; end; buf[0] := 0; try fpwrite(handle, buf, 1); except writeln('Error writing'); halt; end; //try sleep(10); try fpread(handle, buf, 7); except writeln('Error reading'); halt; end; //try writeln('sec : ', bcd2dec(buf[0] AND $7F)); writeln('min : ', bcd2dec(buf[1])); writeln('hour : ', bcd2dec(buf[2] AND $3F)); writeln('WeekDay : ', bcd2dec(buf[3])); writeln('Day : ', bcd2dec(buf[4])); writeln('Month : ', bcd2dec(buf[5])); writeln('Year : ', bcd2dec(buf[6])); fpclose(handle); end.
This experiment went smoothly and quickly the only thing I have left to try is reading/setting GPIO pins on the RPI using FP. And the day isn’t over yet…