I2C EZO component



  • @reitinge Hello thank you for your time

    I appreciate . I'll have a look at these example.
    Thx again.

    Arnaud



  • Hello again everybody.

    I just received my I2c components, and I'm really lost to understand how adapt the i2c example for my hardware.
    I have understand the line of the rexlang MCP3422 ADC, with i2c handle, adress, ect. But I I don't understand the communication itself.

    I have as example for my hardware :

    4.jpg 3.jpg 2.jpg 1.jpg

    With these information I don't understand how I need to adapt the rexlang function made for MCP3422 to match the EZO read/write.

    If I understand well, I would say that :

    Start is : Open I2C;
    I2C adress: is 0x63;
    after I don't know how to code the Read or Write function.
    In the example of MCP3422, the variable are 2 array [3] for bufTx and bufRx;
    and we put 0x88 ( I understand why with the explanation) in the bufTx[0]
    and there is a write count of 1 and read of 2.
    I think it's this part that I need to adapt ?

    And stop is close I2C.

    Does anyone can help me to understand how to modify the code of an I2C example to match my hardware.
    It would be a nice Christmas present for me 😉

    Thanks.

    Arnaud.



  • Hi Arnaud,
    it's always a little bit tricky to get communication done without testing and remotely, but I'll do my best.

    At beginning, it is handy to enable Information messages from Rexygen block in the system log:

    1. Open RexDraw and connect to your Target device (in the menu Target -> Connect or F7 key).
    2. Click on Target menu again and select Configure System Log.
    3. Check the Function block messages -> Information box (as marked on attached figure) and hit the OK button.
      55921c75-19ac-40f6-84e8-c733dd528a1c-image.png

    For I2C communication you should:

    1. Firstly, you should open communication channel on specific bus. This is done only once in the init() method in Rexlang with command i2c_bus_handle = OpenI2C(deviceName);, where deviceName is name of the bus you want to communicate on. For example /dev/i2c-1:
      i2c_bus_handle = OpenI2C("/dev/i2c-1");
      Please check, if communication was established successfuly. You can do that with the Trace() command:
      Trace(traceID,value);
      For example:
      Trace(1,i2c_bus_handle);
      If you run your script, you should see in the Log something like this:
      a719830f-3a01-42c6-a6a1-077d36422833-image.png
      The 0001 value is the traceID and 1 (0x1) is value of i2c_bus_handle. If i2c_bus_value is negative, something went wrong.

    2. Next step is setting address of your device (0x63 for you). This step is done only once too in the init() method: i2c_chip_address = 0x63;

    3. You have to prepare data which you want to send. Use the i2c_bufTx array variable which is prepared in the MCP3422 example. For example on this image
      ad6c2c12-0275-4551-a838-b771f624625d-image.png
      you should set following values to i2c_bufTx array: i2c_bufTx[0] = 1; i2c_bufTx[1] = 57; i2c_bufTx[2] = 46; i2c_bufTx[3] = 53; i2c_bufTx[4] = 54; i2c_bufTx[5] = 48; i2c_bufTx[6] = 0;
      Be aware, in the Example the array has length only 3 bytes and you need 7 bytes. So enlarge the array in Declaration variables section.

    4. Use the I2C() method. This method will send and receive data in one step. You can modify the main() method of MCP3422 example as follow:

    i2c_bufTx[0] = 1;
    i2c_bufTx[1] = 57;
    i2c_bufTx[2] = 46;
    i2c_bufTx[3] = 53;
    i2c_bufTx[4] = 54;
    i2c_bufTx[5] = 48;
    i2c_bufTx[6] = 0;
    
    i2c_write_count = 7; // you are sending 7 bytes
    i2c_read_count = 5; // you are expecting receive 5 bytes long (you probably need to modify it!!!)
    //Sending data via I2C
    i2c_ret_fun = I2C(i2c_bus_handle, i2c_chip_address, i2c_bufTx, i2c_write_count, i2c_bufRx, i2c_read_count);
    

    The answer of your device should be stored in the i2c_bufRx array now. Make sure you read the correct number of bytes and have a long enough array.

    Try some easy write/read command first and let me know, if it works!

    Cheers,
    Jan



  • @reitinge

    Hello again thx for your time.

    When I try to add trace function, I have an error in the during compiling : function 'trace' is not declared ?
    The example that you attach in your response, is when you request data from device. ( so we read data )

    But if I want to write I have this data :

    send.jpg

    So Do I have to generate an array of 5 and send Start, I2c address, write, "the wanted function", stop ?
    And easy test for me is to make a led blinking on the EZo chip :

    find.jpg

    If I understand their example, I need to WRITE find in the EZO and there is no returns values because it's making a led blinking.
    The example with ascii code return, is when I do a reading of the probe for example.
    My question is if I write Find, Do I have to send ( write; find ) And I alerady have the start, with open I2c and adresse, and stop or do I have to send all data ?

    Hope I'm enough clear ?

    Arnaud.



  • Trace() function has capital T. Find Rexlang documentation for details (https://www.rexygen.com/doc/ENGLISH/MANUALS/BRef/REXLANG.html#x270-26900015).

    The start and stop of each message is generated automatically with the I2C command. In main() method, you should need to specify only i2c_bufTx array and number of bytes from this array, which will be send. You can try following for Find example:

    i2c_bufTx[0] = 70;   //F
    i2c_bufTx[1] = 105;  //i
    i2c_bufTx[2] = 110;  //n
    i2c_bufTx[3] = 64;   //d
    i2c_write_count = 4; 
    i2c_read_count = 0; //nothing to read
    //Sending data via I2C
    i2c_ret_fun = I2C(i2c_bus_handle, i2c_chip_address, i2c_bufTx, i2c_write_count, i2c_bufRx, i2c_read_count);
    

    The init () method does not change, nor does the exit() method.



  • @belgacom I'm sorry, decadic ASCII value for "d" is 100, not 64.

    i2c_bufTx[3] =100;   //d
    


  • @reitinge

    I do have a negative result with the trace function .

    here is a print screen of the log and the current BF code :

    trace .jpg

    What could be the error to have the trace at -106.

    Arnaud



  • Error -106 means Invalid parameter. Error codes are documented here: https://www.rexygen.com/doc/ENGLISH/MANUALS/BRef/BRef_ENGap3.html

    • Please, delete the space between Trace and (.
    • Check value of the parameter p0 in the Rexlang block (attached figure). 24b4564a-93f8-4b58-8b55-551866ceadce-image.png
      This is the value which is set into the variable i2c_dev. In my case, it is the bus /dev/i2c-1. This depends on your wiring.
    • Are you sure, you are running the Rexygen program on your Raspberry? The Error: REXLANG open this file type is not possible on this platform indicate, that you might run on your local PC and there is no I2C bus.

    Cheers,
    Jan



  • @reitinge

    Hello, Happy new year. Thanks for your help and sorry for the time lost for my com issue. I was targeting Localhost and not my Pi. Except the fact that command need to be send in Hex and not in Dec, your code works find.

    I'm able to send command and read values back.
    Thanks a lot.

    I still have a couple of question for you :

    1. now I have the reading of my probe in bufRx [1] to [5] in DEC. and I need to convert it in ASCII. (51 46 56 57 54 = 3.896 )
      Is there a function for that, in Rexlang or another FB to use ?

    2. Between a write and a read, I have for example 900ms to wait . So currently I have done 2 Rexlang, 1 to write, 1 to read.
      And I use a timer between both FB. Is there a way to do it directly in Rexlang, or do I have to continue to use 2 block ?
      I didn't find answer in the doc.

    Have a good day.

    Arnaud.



  • @belgacom
    Happy new year to you too. You are welcome. I'm sorry for decadic <-> hexadecimal converting trouble. I usually send values as a hex, but I thought the decimal values would work as well.

    1. For converting DEC/HEX values into string, you can use something like this:
        int i;    
        char message[5];    
        /*bufRx[1] = 51;    
        bufRx[2] = 46;    
        bufRx[3] = 56;    
        bufRx[4] = 57;    
        bufRx[5] = 54;*/    
        for (i=1; i<6; i++)    
      	message[i-1] = bufRx[i];    
        Trace(1,message); 
      
    2. Yes, you can use one Rexlang block for reading / writing. The easiest way is to use some type of simple if-else or switch-case structure in the main() function. Rexlang provides functions as Sleep() or Suspend() (see documentation https://www.rexygen.com/doc/ENGLISH/MANUALS/BRef/REXLANG.html#x270-26900015) but I think the right way is to send a request and periodically checking if the answer received. You should change the period of your task where the Rexlang block is too. https://www.rexygen.com/doc/ENGLISH/MANUALS/BRef/EXEC.html The Rexlang block source code (and all others blocks in the task) are executed only once per period time.

    Best regards,
    Jan



  • @reitinge

    Hello, Happy new year. Hope you are going .
    I tried to use trace with you code up here, but even if the block is returning the correct value of my Ezo components,
    I have an 508 error.

    errore 508 .jpg
    therefore no trace is seen in the log . any idea why 508 error ?

    Anyway even if I hand write 5 values into message[5], how after do I see it on the HMI page.
    If I use a declaration of output like :

    long output(x) message; or string output(x) I can't manage to see values in message.
    How do I proceed ?

    thx

    Arnaud


Log in to reply