How to read I2C without specified device from FB

yledermann
2018-01-25
2023-01-05
  • yledermann - 2018-01-25

    Hello

    i tried several ways to read a word from an i2c device without the need of any (complex) devicedesc.xml and device.library
    I want to read the cap and voltage of a UPS HAT (http://www.raspberrypiwiki.com/images/6/6f/How-to-use-via-i2c.pdf)

    i can read the word from the device with i2cget from terminal

    i2cget -f -y 1 0x36 4 w
    0x7c4d
    

    Is there a way to read those 2 bytes or this word from within a FB?
    I tried something like https://forum.codesys.com/viewtopic.php?f=23&t=6247&p=19944#p19944 but did not succeed.

    Any help will be appreciated.
    Thanks in advance

     
    • shinxis - 2023-01-05

      Hi! I'm a newbie and spent too much time with the same problem. Here's a solution that hopefully saves some time for someone else.

      First of all, add I2C Library; Choose Library Manager device, click Add Library button, search for i2c and select "i2c". Right-click I2C in the Devices list, select Add Device, I2C master. We can now use the functions in the Raspberry Pi Peripherals package (included in Codesys) or whatever you're on. Here's two function Blocks that'll do the magic.

      // ---------- PLC_PRG: Defines
      I2C_read:I2C_read;
      I2C_write:I2C_write;
      // ---------- PLC_PRG: The code. Here you call them.
      I2C_read(Device,Register,Data);
      I2C_write(Device,Register,Data);
      
      // ---------- READING: Defines
      FUNCTION_BLOCK I2C_read EXTENDS i2c
      VAR_INPUT
          Device:BYTE;   // Example: 16#76 (BMP280 pressure/temperature sensor)
          Register:BYTE; // Example: 16#D0
      END_VAR
      VAR_OUTPUT
          Data:BYTE;     // Example: 16#58
      END_VAR
      // ---------- READING: The code
      SUPER^(); // Needed, because of 'EXTENDS' in the defines.
      I2C_master.write(usiAddress:=Device, pbyBuffer:= ADR(Register), nBufferLen:= 1);
      I2C_master.read(usiAddress:=Device, pbyBuffer:= ADR(Data), nBufferLen:= 1); 
      
      // ---------- WRITING: Defines
      SUPER^();
      FUNCTION_BLOCK I2C_write EXTENDS i2c
      VAR_INPUT
          Device:BYTE;
          Register:BYTE;
          Data:BYTE;
      END_VAR
      VAR
          WriteOutBuffer : ARRAY[0..1] OF BYTE;
      END_VAR
      // ---------- WRITING: The code
      WriteOutBuffer[0]:=Register;
      WriteOutBuffer[1]:=Data;
      I2C_master.write(usiAddress:=Device, pbyBuffer:= ADR(WriteOutBuffer), nBufferLen:= 2); 
      
       

      Related

      Talk.ru: 1

  • eschwellinger

    eschwellinger - 2018-01-26

    Hi,

    for I2C guess this example here would do the job:
    l viewtopic.php?f=23&t=6247&p=19944#p19944 l

    for SPI:
    "c:\Users\<yourwindowsusername>\CODESYS Control for Raspberry PI\3.5.12.0\Examples\PiFace_FB.project"
    BR
    Edwin</yourwindowsusername>

     
  • yledermann - 2018-01-26

    Hi Edwin

    Thank you for the fast answer.
    That was the example i already tried.
    But i found another one...
    https://forum-raspberrypi.de/forum/thread/32601-neubau-hardware/?postID=304583#post304583
    This example was the missing point.
    i need to write to the register before i read it back...

    just in case someone else is fighting with the basics of i2c here is my working code:

    FUNCTION_BLOCK UPSHAT
    VAR_INPUT
    Β  Β usiAddress : USINT := 16#36;
    END_VAR
    VAR_OUTPUT
    Β  Β rVoltage : REAL := 0;
    END_VAR
    VAR
    Β  Β // Registers
    Β  Β byRegVoltage Β  Β : BYTE := 16#02;
    Β  Β baReadBufferV : ARRAY [0..1] OF BYTEΒ  := [2(0)];
    Β  Β nReadLenght: DINT;
    END_VAR
    // Register Spannung auf Bus schreiben...
    I2C_master.write(usiAddress, ADR(byRegVoltage), 1);Β  
    // ... und Wert lesen.
    nReadLenght := I2C_master.read(usiAddress, ADR(baReadBufferV), 2);
    // wenn zwei Bytes gelesen worden sind die Spannung berechnen uns ausgeben
    IF nReadLenght = 2 THEN
    // Daten zwischenspeichern
    //swap_word := MEM.PackBytesToWord(baReadBuffer[1],baReadBuffer[0]);
    //rVoltage := (swap_word * 78.125 / 1000000);
    rVoltage := (MEM.PackBytesToWord(baReadBufferV[1],baReadBufferV[0]) * 78.125 / 1000000);
    END_IF;
    
     

    Related

    Talk.ru: 1

  • eschwellinger

    eschwellinger - 2018-01-26

    Hi,
    thanks for the feedback,
    if you want you could publish your application here:
    Raspberry Pi: List of available example applications
    think other user would be very thankful for these kind of Information and applications.
    BR
    Edwin

     
  • powertrick - 2021-02-15

    Yiedermann thank you for the snippet as my codesys is reading an i2c slave.....any chance you know how to write to a slave as I tried anything I could think of. Seems the usage mimics the I2C method comparing the read so for write I tried below:

    datatoread:  ARRAY [0..1] OF BYTE  := [2(0)];
    
            I2C_master.write(16#68, 16#15, 1);  
            I2C_master.write(16#68, ADR(datatostore), 2);
    
     
    πŸ‘
    1
    • audi0615 - 2021-03-09

      Hi
      Have you made it working?
      I am also looking for how to write a value to a register with I2C Master write method.
      I would appreciate if you can share your code.

       
    • krishemanth - 2021-03-23

      Hi powertrick,
      i am trying to read and write data to registers of a controller from my arm board through Codesys.
      if you have managed to make it work, can you share the code. i couldn't find an example project for this.

      Thanks,
      -Kris

       
      • powertrick - 2021-03-23

        Which I2C part?

        Get Outlook for Androidhttps://aka.ms/AAb9ysg


        From: talk@forge.forge.codesys.com talk@forge.forge.codesys.com on behalf of krishemanth forge@codesys.com
        Sent: Tuesday, March 23, 2021 5:29:24 PM
        To: [forge:talk] Runtime@talk.forge.forge.codesys.com
        Subject: [forge:talk] Re: How to read I2C without specified device from FB

        Hi powertrick,
        i am trying to read and write data to registers of a controller from my arm board through Codesys.
        if you have managed to make it work, can you share the code. i couldn't find an example project for this.

        Thanks,
        -Kris


        How to read I2C without specified device from FBhttps://forge.codesys.com/forge/talk/Runtime/thread/010acaa90c/?limit=25#470d/ec5c


        Sent from forge.codesys.com because you indicated interest in https://forge.codesys.com/forge/talk/Runtime/

        To unsubscribe from further messages, please visit https://forge.codesys.com/auth/subscriptions/

         
        • krishemanth - 2021-03-23

          powertrick thanks for your quick response
          you mean i2cbus-number by the i2c part? or the slave device?

          its a controler stm with slave address of 0x18 on i2c-1 bus
          iam doing something like i2cset -y 1 0x18 0x02 0x00 0x00 0x72 0x80 0x00 0x00 0x00 0x00 0x72 0x72 0x72 0x72 0x42 i from my target board.
          how can i do the same from the codesys

          thanks in advance,
          -kris

           

          Last edit: krishemanth 2021-03-23
          • powertrick - 2021-03-23

            I asked about the slave device as some need a 8 bit and others 16 bit data word. I posted below all nicely formatted however the server rejected it so it's slightly less now formatted below.

            I managed to get the new win10 desktop power apps also using the I2C tools cmds and it works well

            i2cset -y 0 0x68 0x0D 0x0 w (reg 13d,15)
            i2cset -y 0 0x68 0x14 0x0 w (reg 20d,4)
            Bear in mind the following:
            We are interacting with a device with 16 bit data words so
            adjust accordingly for 8 bit data words
            In our case we created a function method to read and a method
            to write the devices and this is not shown supporting small/big endian
            and also 8/16 bit data words so it can get very complex
            We struggled so spent some time to master I2Cget and I2Cset
            (I2Ctools) on the linux terminal to cross check the device
            interaction..do this first and master it to save your sanity ie.
            1) i2cset -y 0 0x68 0x15 0x8000 w //will set the data reg 21d as
            0x8000
            2) i2cget -y 0 0x68 0x15 w //this will get the data in 16 bit
            format just written above...omit the 'w' for 8 bit words. The '0' is our
            specific I2C port...maybe yours is 1 or 2 or 3
            This cycles fast enough for us now at 10ms tasks to do repeated
            reads or writes however in future we will streamline this with a I2C
            bus analyzer to have repeats much faster. Read generally can be fast
            although some device have a buffer write time of several ms so
            consult the datasheet of the device you are using.
            As the I2C protocol is open drain the I2Ctools and Codesys
            debug can be used concurrently at the same time to cross check each
            other.

            //ReadFromDevice method-Read from I2C device one 16bit
            word at a time

            VAR
            datatoget: ARRAY [0..2] OF WORD := [2(0)];
            VAR_END
            I2C_master.write(16#68, 16#15, 1);
            I2C_master.read(16#68, ADR(datatoget), 2); //2 the is for 2
            nibbles
            If you are writing into device 16 bit data words then here is
            something as a guide from our code as the array needs to be in a 16
            bit word
            VAR
            datatostore: ARRAY [0..3] OF WORD := [2(0)];
            VAR_END
            datatostore[0] := 16#15;
            datatostore[1] :=
            OSCAT_BASIC.BYTE_OF_DWORD (regdata_to_write, 0);
            //Buffer low nibble of the 16 bit data word
            datatostore[2] :=
            OSCAT_BASIC.BYTE_OF_DWORD (regdata_to_write, 1);
            //Buffer high nibble of the 16 bit data word
            //WriteToDevice method-Write to I2C device one 16bit word at
            a time
            I2C_master.write(16#68, 16#15, 1);
            I2C_master.write(16#68, ADR(datatostore), 3);

            Get Outlook for Androidhttps://aka.ms/AAb9ysg


            From: talk@forge.forge.codesys.com talk@forge.forge.codesys.com on behalf of krishemanth forge@codesys.com
            Sent: Tuesday, March 23, 2021 8:06:55 PM
            To: [forge:talk] Runtime@talk.forge.forge.codesys.com
            Subject: [forge:talk] Re: How to read I2C without specified device from FB

            powertrick thanks for your quick response
            you mean i2cbus-number by the i2c part? or the slave device?

            its a controler stm with slave address of 0x18 on i2c-1 bus
            iam doing something like i2cset -y 2 0x18 0x02 0x00 0x00 0x72 0x80 0x00 0x00 0x00 0x00 0x72 0x72 0x72 0x72 0x42 i from my target board.
            how can i do the same from the codesys

            thanks in advance,
            -kris


            How to read I2C without specified device from FBhttps://forge.codesys.com/forge/talk/Runtime/thread/010acaa90c/?limit=25#470d/ec5c/2b17/cc31


            Sent from forge.codesys.com because you indicated interest in https://forge.codesys.com/forge/talk/Runtime/

            To unsubscribe from further messages, please visit https://forge.codesys.com/auth/subscriptions/

             

            Related

            Talk.ru: 1
            Talk.ru: 2

            • krishemanth - 2021-03-24

              powertrick Thank you for having patience and supporting me. Above example helped me.

              Thanks,
              -Kris.

               
              • powertrick - 2021-03-24

                After a lot of frustration the key to us getting this working well was to practice with I2Ctools until we knew exactly what we were doing. We then took several weeks to develop a rubust FB that could be controlled through a OOP method interface for 8 or 16 bits and a few other features. In our FB we added small/big endian support with Pragma IF statements by simply switching the datatostore[1] and datatostore[2] around. As I2C to Azure is the crux of our application it was the best thing we did to spend a lot of time with our I2C FB until it was robust.

                 

                Related

                Talk.ru: 1
                Talk.ru: 2

  • powertrick - 2021-03-10

    .

     
    πŸ‘
    1

    Last edit: powertrick 2021-03-10
  • yledermann - 2021-03-10

    Hi @audi0615 and @powertrick

    I just discovered your pm in my spam folder.

    Im sorry but im not using codesys with i2c at the moment.
    and in 2018 i was just reading some bytes from a UPS Hat and never wrote to an i2c device.

    I have not that many experience with i2c.

    What kind of i2c device you want to write to?

     
    • audi0615 - 2021-03-12

      Thanks for your reply
      LSM303 accelerometer and magnetometer.
      I have decided to use library + xml file.

       

Log in to post a comment.