Hello,
I am trying to use the I2c bus on the Raspberrypi SBC.
I ported this code from a little C pogram I did.
Both fpioctl and fpwrite return -1.
The C version uses the constant I2C_SLAVE which seems to hold 1795, but fp does not have this constant defined.
Can someone point me in the right direction on what I am doing wrong.
When I run this code, everything runs but the device does not get
updated.
Thanks!
Alex
The function below just sents one byte of data (number 9) to Register 8 on the DS1307.
program project1;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
BaseUnix,Classes, sysutils;
{$R *.res}
Procedure InitI2cDevice();
const
p : PChar = '89'; //Characters to sent 8=RAM Register 9=Value
I2C_SLAVE = 1795; //?? Got 1795 from C-Funtcion
Var
iwf,iio : integer;
fd, address : Cint;
paddress : ^integer;
begin
address := $68; //Device Address DS1307 RTC
paddress := @address; //Pointer to Device Address
fd := fpopen('/dev/i2c-0',O_WrOnly); //Open the I2C bus
iio:= fpioctl(fd, I2C_SLAVE, paddress);
iwf := fpwrite(fd, p[0], 2); //write to the Device
//fpioctl and fpwrite both return -1
writeln('After fpwrite: ' + #13 + #10 + 'FileRet#: ' + Inttostr(fd) + ' fpwriteRet#: ' + IntToStr(iwf) + ' fpioctl#: ' + IntToStr(iio));
fpclose(fd);
end;
begin
InitI2cDevice;
readln;
end.
!! UPDATED !!!
Here is some working code for the DS1307 RTC. This is just an example and needs some better error handling etc. But I tested it and it works with my DS1307. On newer raspberrypi's (Made in the UK), the device may change to /dev/i2c-1.
Have fun!
program project1;
{$mode objfpc}{$H+}
{$R *.res}
uses
cthreads, BaseUnix,Classes, sysutils;
Const
I2C_SLAVE = 1795;
Var
buf : Array[0..20] of Byte;
aDate : Array[0..4] of Byte; //Array to hold date components 0=Start address
aTime : Array[0..3] of Byte; //Array to hold Time components 0=Start address
aValue : Array[0..3] of Byte; //Array to hold Time components 0=Start address
ds1307 : Integer; //Variable to hold file handle. Used Device Name for clarity. Use multiple variables to talk to multiple devices
// Helper function to convert Bcd To Byte
Function bcdtoByte(bcd: Byte): Byte;
begin
bcdtoByte := (((bcd shr 4) * 10 + (bcd and $0f)));
end;
// Helper function to convert Byte to Bcd
Function btobcd(b: Byte): Byte;
begin
btobcd := (((b div 10) shl 4) + (b mod 10));
end;
//Function to initialize device. iDevAddr = Address of the i2c device
Function InitI2cDevice(devpath: String; iDevAddr: Cint; var iInst: Integer):Integer;
Var
iio : integer;
begin
Try
iInst := fpopen(devpath,O_RDWR); //Open the I2C bus in Read/Write mode
iio:= FpIOCtl(iInst, I2C_SLAVE, pointer(iDevAddr)); //Set options
If (iio = 0) and (iInst > 0) Then InitI2cDevice := iInst Else InitI2cDevice := -1;
Except
InitI2cDevice := -1;
End;
end;
//can be used for writing any one register with or without BCD conversion
Function setRegister(startregno: Integer; val: Byte; cbcd: boolean; var iInst: Integer):Integer;
begin
Try
buf[0] := startregno;
If cbcd = true then
Begin
buf[1] := btobcd(val);
fpwrite(iInst, buf[0], 2);
end
Else
Begin
buf[1] := val;
fpwrite(iInst, buf[0], 2);
End;
Except
setRegister := -1;
End;
setRegister := 1;
end;
//can be used for reading any one register with or without BCD conversion
Function getRegister(val: Byte; cbcd: boolean; var iInst: Integer):Byte;
Var
iRet : Byte;
begin
Try
buf[0] := val;
If cbcd = true then
Begin
fpwrite(iInst, buf[0], 1);
fpread(iInst, iRet, 1);
iRet := btobcd(iRet);
end
Else
Begin
fpwrite(iInst, buf[0], 1);
fpread(iInst, iRet, 1);
End;
Except
getRegister := -1;
End;
getRegister := iRet;
end;
//can be used for writing multiple register with or without BCD conversion
//regs[0] = first Register, regs is an array to hold values
//cbcd = True or False convert regs to BCD or not
//Values in the array have to be consecutive on the device
//BCD conversion will not affect regs[0].
Function setNRegister(regs: Array of Byte; cbcd: boolean; var iInst: Integer):Integer;
Var
i : integer;
ifpw : Integer;
begin
Try
If cbcd = true then
Begin
buf[0] := regs[0];
For i := 1 to High(regs) do
Begin
buf[i] := btobcd(regs[i]);
//Writeln('Buf: ' + IntTostr(i+1) + ' Val: ' + intToStr(regs[i]) + ' Write: ' + IntToStr(High(regs)+1));
end;
end
Else
Begin
For i := 0 to High(regs) do
Begin
buf[i] := regs[i];
//Writeln('Buf: ' + IntTostr(i) + ' Val: ' + intToStr(regs[i]) + ' Write: ' + IntToStr(High(regs)+1));
end;
End;
ifpw := fpwrite(iInst, buf[0], High(regs)+1);
//Writeln('ifpw: ' + IntToStr(ifpw));
Except
setNRegister := 1;
End;
setNRegister := 0;
end;
//can be used for getting multiple register with or without BCD conversion
//regs[0] = first Register, regs is an array to hold values
//cbcd = True or False convert regs to BCD or not
//Values in the array have to be onsecutive on the device
Procedure getNRegister(var regs: Array of Byte; cbcd: boolean; var iInst: Integer);
Var
ifpw, ifpr, i : Integer;
Begin
Try
ifpw := fpwrite(iInst, regs[0], 1);
ifpr := fpread(iInst, regs, 3);
If cbcd = True then
Begin
For i := 0 to High(regs) do regs[i] := bcdtoByte(regs[i])
End;
Except
Writeln('Error, Fpwrite: ' + IntToStr(ifpw) + ' fpread: ' + IntToStr(ifpr));
End;
end;
//Main Program
Begin
InitI2cDevice('/dev/i2c-0',$68,ds1307); //Init must always be called first for any device
aDate[0] := 3; //0 = Start Register, 3 for Date on DS1307
aDate[1] := 7; //1 = Day 1-7
aDate[2] := 14; //2 = Date 1-31
aDate[3] := 7; //3 = Month 1-12
aDate[4] := 12; //4 = Year 0-99
aTime[0] := 0; //0 = Start Register 0 for Time on DS1307
aTime[1] := 0; //Seconds 0-59
aTime[2] := 3; //Minutes 0-59
aTime[3] := 5; //Hours 0-23 Normal can be changed to 1-12
aValue[0] := 8; //8 = Start Register, 8 for first GP reg on DS1307
aValue[1] := 99;
aValue[2] := 2;
aValue[3] := 3;
setNRegister(aDate,True,ds1307); //Set Multiple Register Starting at Address 3 (aDate[0])
setNRegister(aTime,True,ds1307); //Set Multiple Register Starting at Address 0 (aTime[0])
setRegister(8,177,False,ds1307); //Set Register 8 first GP Ram Register no BCD
Writeln('Reg 8 Value: ' + IntToStr(getRegister(8,False,ds1307))); //Get First GP RAM Register no BCD
Writeln('Day of Month: ' + IntToStr(getRegister(4,True,ds1307))); //Get Day of Month on DS1307 = Reg 04h with BCD
setNRegister(aValue,False,ds1307); //Set Multiple GP Register Starting at Address 8 (first GP Register)
getNRegister(aValue,false,ds1307); //Reads multiple registers from device
writeln('Read multiple Regs: 1: ' + IntToStr((aValue[0])) + ' 2: ' + IntToStr((aValue[1])) + ' 3: ' + IntToStr((aValue[2])));
fpclose(ds1307); //close device handle
end.