Recent

Author Topic: Example on how to read/write I2C devices on Raspberry Pi?  (Read 1656 times)

BosseB

  • Jr. Member
  • **
  • Posts: 92
Example on how to read/write I2C devices on Raspberry Pi?
« on: November 12, 2019, 12:14:35 pm »
Hi, is there some on-line examples somewhere on how to interface to devices (RTC, sensors) and EEPROM from a FreePascal program?
I am working on a project that uses I2C devices on a plug-in board as well as GPIO I/O.
I can handle the GPIO stuff using the PiGpio unit.
But I have not found any similar thing for the I2C connected devices...

I have heard about BaseUnix unit but I also need an I2C example or two if BaseUnix holds the needed resources.

Thanks.
--
Bo Berglund
Sweden

MarkMLl

  • Sr. Member
  • ****
  • Posts: 285
Re: Example on how to read/write I2C devices on Raspberry Pi?
« Reply #1 on: November 12, 2019, 01:05:59 pm »
Bo, attached is something that worked for me. It's a bit crude in places but illustrates running on a Raspberry Pi and using no non-standard libraries tto talk to an Arduino-compatible "piggy-backed" on top https://rasp.io/duino/ via I2C.

MarkMLl
Turbo Pascal v1 on CCP/M-86, multitasking with LAN and graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.

Thaddy

  • Hero Member
  • *****
  • Posts: 9285
Re: Example on how to read/write I2C devices on Raspberry Pi?
« Reply #2 on: November 12, 2019, 01:44:17 pm »
The free TMS components for Raspberry Pi comes with units you may want to examine.
also related to equus asinus.

avra

  • Hero Member
  • *****
  • Posts: 1733
    • Additional info
Re: Example on how to read/write I2C devices on Raspberry Pi?
« Reply #3 on: November 12, 2019, 05:21:59 pm »
is there some on-line examples somewhere on how to interface to devices (RTC, sensors) and EEPROM from a FreePascal program?
Start here: https://wiki.freepascal.org/Lazarus_on_Raspberry_Pi
ct2laz - Conversion between Lazarus and CodeTyphon
bithelpers - Bit manipulation for standard types
pasettimino - Siemens S7 PLC lib

BosseB

  • Jr. Member
  • **
  • Posts: 92
Re: Example on how to read/write I2C devices on Raspberry Pi?
« Reply #4 on: November 14, 2019, 08:18:53 pm »
OK thanks.
I am now struggling with how to actually read the content of an I2C connected EEPROM chip.
It is using the default address $50 and I would like to know if there is a way to read more data than one byte per operation.
Say in the extreme I want to read the full contents of the EEPROM starting at address 0.
Is there a single i2c command one can issue to the Raspbian driver, which would return the data?
The archive MarkMLl attached is aimed at talking to an i2c connected Arduino board and it uses the following to read the Arduino specific data(, I have removed a number of calls to "Assert", which I don't know what it is):

Code: Pascal  [Select]
  1.   function getResponse(Handle: cint): responseType;
  2.   begin
  3.     response := '........................';     (* 24 characters*)
  4.     Sleep(100);                         (* Milliseconds*)
  5.     if fpRead(Handle, response[1], 24) <> 24 then
  6.       if response[1] = '.' then         (* No response at all*)
  7.         exit(none)
  8.       else                              (* Didn't get to \r *)
  9.         exit(bad);
  10.     if (Pos('EIO', response) <> 1) or (Pos(#$0d, response) = 0) then
  11.       exit(bad)                         (* Not quite right*)
  12.     else begin                          (* Got it*)
  13.       SetLength(response, Pos(#$0d, response) - 1);
  14.       exit(ok)
  15.     end
  16.   end { getResponse } ;
  17.  
  18.  
  19. begin
  20.   fd := fpOpen('/dev/i2c-1', O_RDWR);
  21.   scratch := fpIoctl(fd, I2C_SLAVE, slave);
  22.   scratch := fpWrite(fd, ei[1], 3);  // <== What does this do???
  23.   case getResponse(fd) of
  24.     none: WriteLn('Read timed out');
  25.     bad:  WriteLn('Read incomplete')
  26.   otherwise
  27.     WriteLn(response)
  28.   end;
  29.   scratch := fpClose(fd);
  30.   WriteLn('OK')
  31. end.

I assume that the sleep is inserted in order for the system to have time to read the data into some buffer.
It seems like this expects EXACTLY 24 bytes data back, could this be right?
The call to fpWrite uses the file handle to the i2c device, plus the address to the buffer which shall receive the data. But what does the 3 mean? It could not really be the length of data expected? It is supposed to be 24 bytes, right? What I can see the last argument is the length of data...

So if I do not communicate over i2c like rs232 to another party, but want to read a specific amount of data from say an EEPROM, how is that set up?


--
Bo Berglund
Sweden

avra

  • Hero Member
  • *****
  • Posts: 1733
    • Additional info
Re: Example on how to read/write I2C devices on Raspberry Pi?
« Reply #5 on: November 15, 2019, 10:27:38 am »
I would like to know if there is a way to read more data than one byte per operation.
If there is no ready to use library providing such high level feature, then you have to get out of your developer comfort zone, dig into the world of electronics and learn the craft of reading datasheets. For example, if your i2c eeprom device is 24LCxx family (other families are sometimes quite different), then you find datasheet for it on the net and try to understand as much as you can. For the question you have, you search for the supported features and see what is of interest. Datasheet says that Byte Write, Page Write, Current Address Read, Random Read and Sequential Read I2C operations (functions) are available. So, for the most optimal block read/write you should use these 24LCxx internal I2C functions. For sub optimal block read/write you could forget all said, and just use a simple loop to read/write individual bytes. Since I2C protocol is byte based anyway, my wild guess is that in best case optimized read/write is about 2 times faster. If you can live without such speed then you can happily get away with suboptimal simple read/write loop. If speed is important, then you should also check what is the highest speed that your I2C eeprom chip supports and then initialize your I2C channel to that speed. You will agree that reading something with 100kbits/s is not he same as reading it with 400 Kbit/s, 1Mbit/s or 3,2 Mbit/s.

Using BaseUnix may be OK for classic linux developers, but if you find your self in position of translating some existing Arduino I2C library to FPC then you may want to look for something different and microcontroller like programming lib. All other libraries mentioned on that wiki page are like that. I could not find linux example, but on Atmel AVR accessing 24LCxx I2C eeprom looks like this.

Btw, linux kernel already has at24 and some other eeprom drivers. It will be good to read some comments about it first. There is also a custom at24 block driver so you might want to explore that path, too.
« Last Edit: November 15, 2019, 10:59:13 am by avra »
ct2laz - Conversion between Lazarus and CodeTyphon
bithelpers - Bit manipulation for standard types
pasettimino - Siemens S7 PLC lib

kupferstecher

  • Sr. Member
  • ****
  • Posts: 324
Re: Example on how to read/write I2C devices on Raspberry Pi?
« Reply #6 on: November 15, 2019, 11:58:26 am »
@BosseB: You can use the pascalio lib. The usage is easier to understand than the code you posted.

By the way, be careful with the address, some datasheets talk about the 7-bit address, which is the first 7 bit of a byte, others talk about the 8-bit address which contains the least significant bit for the direction (read/write). So your $50 could be a $A0 or a $28 as well.

As avra said, you have to check the datasheet on how to access the chip. Normally you read (write) a byte or word out of (into) a register. The sequence then is something like slave-adress/register-address/data with start/stop conditions and acknowledge in certain order in between. A library like pascalio provides functions for that certain sequence already. E.g. WriteRegByte(aRegAddress, aData);
The chip may offer a continuous reading of the eeprom data (sending the address only once), but then you have to understand the protokoll, so its easier to do it "bytewise" with the library function (calling it for each byte you want to read). In the end its only a question of speed.

Here a snippet of my code accessing a PCA9685 (LED driver chip) using pascalio.

Code: Pascal  [Select]
  1. INTERFACE
  2. Uses fpi2c;
  3.  
  4. Type TPCA9685 = class
  5.   {$IFDEF RASPBERRY}
  6.   I2CPort: TI2CLinuxDevice; {$ENDIF}
  7.   Constructor Create(AAddress: ptrInt; AName: String = 'I2C');
  8. [...]
  9. end;
  10.  
  11. IMPLEMENTATION
  12. Constructor TPCA9685.Create(AAddress: ptrInt; AName: String = 'I2C');
  13. var
  14.   newMode1: byte;
  15.   ii: Integer;
  16. begin
  17.   Name:= AName;
  18.   Status.Write(Name+': I2C initialisation on address '+ Inttostr(AAddress)); Application.ProcessMessages;
  19.  
  20.  
  21.   if I2CPort <> nil then I2CPort.Free;
  22.   I2CPort:= TI2CLinuxDevice.Create(AAddress,1);
  23.   sleep(100);
  24.   try
  25.     I2CPort.WriteRegByte(regMODE2, bitOUTDRV);
  26.     I2CPort.WriteRegByte(regMODE1, bitALLCALL);
  27.     sleep(100); //wait for oscillator
  28.     newMode1:= I2CPort.ReadRegByte(regMODE1);
  29.     newMode1:= newMode1 and not bitSLEEP; //wake up (reset sleep)
  30.     I2CPort.WriteRegByte(regMODE1, newMode1);
  31.     sleep(100); //wait for oscillator
  32.  
  33.     SetPWMFreq(500);
  34.  
  35.   except
  36.     Status.Write(Name+': Error while initialisation of I2C');
  37.   end;
  38.  
  39. [...]
  40. end;
  41.  
  42.  

BosseB

  • Jr. Member
  • **
  • Posts: 92
Re: Example on how to read/write I2C devices on Raspberry Pi?
« Reply #7 on: November 15, 2019, 12:03:25 pm »
@avra,
Quote
If there is no ready to use library providing such high level feature, then you have to get out of your developer comfort zone, dig into the world of electronics and learn the craft of reading datasheets.
Thanks for the pointers, but the problem I have is that I cannot get my head around the operating system interface in this case.

I have done a fair bit of embedded microcontroller development (Microchip PIC) including interfacing the I2C EEPROM devices. And it has always been pretty simple when you have access to the actual pins on the device. I stored a whole lot of config data on these EEPROMs for the PIC projects.
And I had the opportunity to help other PIC developers as well, see here for help on bit-banging I2C.

But the problem here for me is that the EEPROM sits on the other side of Linux as viewed from my side...
And I am not particularly insightful on the inner workings of Linux, that is why I am asking around here...
For high level work I have used Delphi since about 1995 and switched to FreePascal/Lazarus about 6-7 years ago.

--
Bo Berglund
Sweden

BosseB

  • Jr. Member
  • **
  • Posts: 92
Re: Example on how to read/write I2C devices on Raspberry Pi?
« Reply #8 on: November 15, 2019, 12:08:34 pm »
@BosseB: You can use the pascalio lib. The usage is easier to understand than the code you posted.

By the way, be careful with the address, some datasheets talk about the 7-bit address, which is the first 7 bit of a byte, others talk about the 8-bit address which contains the least significant bit for the direction (read/write). So your $50 could be a $A0 or a $28 as well.

As avra said, you have to check the datasheet on how to access the chip. Normally you read (write) a byte or word out of (into) a register. The sequence then is something like slave-adress/register-address/data with start/stop conditions and acknowledge in certain order in between. A library like pascalio provides functions for that certain sequence already. E.g. WriteRegByte(aRegAddress, aData);
The chip may offer a continuous reading of the eeprom data (sending the address only once), but then you have to understand the protokoll, so its easier to do it "bytewise" with the library function (calling it for each byte you want to read). In the end its only a question of speed.
Thanks, could you specify how I can find pascalio. Googling it draws a blank for me...
--
Bo Berglund
Sweden

MarkMLl

  • Sr. Member
  • ****
  • Posts: 285
Re: Example on how to read/write I2C devices on Raspberry Pi?
« Reply #9 on: November 15, 2019, 12:35:56 pm »
@avra,
Quote
If there is no ready to use library providing such high level feature, then you have to get out of your developer comfort zone, dig into the world of electronics and learn the craft of reading datasheets.
Thanks for the pointers, but the problem I have is that I cannot get my head around the operating system interface in this case.

Bo, are you doing your usual trick of not reading all the messages posted in response to your query? I gave you an example of the low-level OS interface several days ago- did you read it?

MarkMLl
Turbo Pascal v1 on CCP/M-86, multitasking with LAN and graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.

BosseB

  • Jr. Member
  • **
  • Posts: 92
Re: Example on how to read/write I2C devices on Raspberry Pi?
« Reply #10 on: November 15, 2019, 02:03:31 pm »
@avra,
Quote
If there is no ready to use library providing such high level feature, then you have to get out of your developer comfort zone, dig into the world of electronics and learn the craft of reading datasheets.
Thanks for the pointers, but the problem I have is that I cannot get my head around the operating system interface in this case.

Bo, are you doing your usual trick of not reading all the messages posted in response to your query? I gave you an example of the low-level OS interface several days ago- did you read it?
What do you mean by "usual trick"?
I thought that these forums are the place to ask when you get stuck on something...
And, yes I downloaded your file and I have tried to apply it too as you could well see a few posts above where I show parts of your code...

But I have not been able to understand how I can use it for my use case yet.
It seems to be about communicating terminal-style with an Arduino and I am not doing that type of process. Instead I want to read from an EEPROM at a specific address a certain number of bytes using the Linux (Raspbian) functions on a Raspberry Pi system.

Today I finally received my EEPROM IC:s (DIP packages so I can prototype) and I will breadboard one and hook it up to the RPi and see what can be done. I will for sure try to adapt your code, if I can.
--
Bo Berglund
Sweden

MarkMLl

  • Sr. Member
  • ****
  • Posts: 285
Re: Example on how to read/write I2C devices on Raspberry Pi?
« Reply #11 on: November 15, 2019, 02:59:04 pm »
That's using BaseUnix on an RPi to talk to an I2C slave. I don't believe that the fact that the slave is implemented by an Arduino is relevant.

Now, what are you having problems with? Have you looked for and read the description of the I2C ioctl()?

As (I think it was) Avra pointed out, you have to understand the format of the command the slave expects and the format of the return. In the example I have you, the command was a short sequence of characters and the response a lightly longer one.

MarkMLl
Turbo Pascal v1 on CCP/M-86, multitasking with LAN and graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.

avra

  • Hero Member
  • *****
  • Posts: 1733
    • Additional info
Re: Example on how to read/write I2C devices on Raspberry Pi?
« Reply #12 on: November 15, 2019, 04:15:35 pm »
Quote
If there is no ready to use library providing such high level feature, then you have to get out of your developer comfort zone, dig into the world of electronics and learn the craft of reading datasheets.
Thanks for the pointers, but the problem I have is that I cannot get my head around the operating system interface in this case.

I have done a fair bit of embedded microcontroller development (Microchip PIC) including interfacing the I2C EEPROM devices.
Then I don't get it why don't you try out any of the microcontroller like libraries mentioned in the RPi wiki page? It should be much closer to your PIC experience then BaseUnix.
ct2laz - Conversion between Lazarus and CodeTyphon
bithelpers - Bit manipulation for standard types
pasettimino - Siemens S7 PLC lib

kupferstecher

  • Sr. Member
  • ****
  • Posts: 324
Re: Example on how to read/write I2C devices on Raspberry Pi?
« Reply #13 on: November 15, 2019, 06:52:52 pm »
Thanks, could you specify how I can find pascalio. Googling it draws a blank for me...
Here's the link:
https://github.com/SAmeis/pascalio

BosseB

  • Jr. Member
  • **
  • Posts: 92
Re: Example on how to read/write I2C devices on Raspberry Pi?
« Reply #14 on: November 15, 2019, 07:14:34 pm »
Quote
If there is no ready to use library providing such high level feature, then you have to get out of your developer comfort zone, dig into the world of electronics and learn the craft of reading datasheets.
Thanks for the pointers, but the problem I have is that I cannot get my head around the operating system interface in this case.

I have done a fair bit of embedded microcontroller development (Microchip PIC) including interfacing the I2C EEPROM devices.
Then I don't get it why don't you try out any of the microcontroller like libraries mentioned in the RPi wiki page? It should be much closer to your PIC experience then BaseUnix.
Because on Linux the I/O is owned by the operating system as I understand it. On a PIC or AVR one can pretty much do whatever on the pins without having to invoke the OS.
But it seems like the way to go is something like this:
Read data from the device
- open the I2C channel itself (as a file, I guess)
- write a command consisting of the device address with the lsb set to the read state plus the start address in the EEPROM
- read the wanted number of bytes from the device
- close the I2C device

Writing seems to be a bit like that except now the LSB on the address is set to the write state
- open the I2C channel itself (as a file, I guess)
- write a command consisting of the device address plus the start address in the EEPROM
- write the wanted number of bytes from the device (repeat the same 1-byte write command over and over?)
- close the I2C device

I have just connected my EEPROM to the RPi and verified it appears on address $50.
So now I will have to make a small test program with min overhead to test this.

--
Bo Berglund
Sweden