4 years, 7 months ago.

I2c problem with EZO ph sensor

Hi everyone,

I'm having a hard time communicating with my ph sensor in I2C.

I'm using a nrf51-DK from nordic semiconductor.

Here's my sensor datasheet : http://www.atlas-scientific.com/_files/_datasheets/_circuit/pH_EZO_datasheet.pdf?

Here's my code :

include the mbed library with this snippet


#include "mbed.h"
#include <string>

Serial pc(USBTX, USBRX); // tx, rx
I2C i2c(p30, p7); // SDA, SCL

//const int addr = 0x63;
const int addr = 0x63 << 1;

//Variables
char cmdData[1];
char ezodata[10];
string ezovalue;
string cmdvalue;

int main()
{
    i2c.frequency(2000000);

    pc.printf("\n -------------- Clearing ezodata \r\n");
    for (int i=0; i<sizeof(ezodata); i++) {
        ezodata[i] = 0;
        int arrayval = ezodata[i];
        ezovalue = ezodata[i];
        pc.printf(" buff: %d        ASCII: %s\r\n", arrayval, ezovalue.c_str());
    }

    while(1) {

        cmdData[0] = 'R'; // command to ask for a ph reading

        pc.printf("\n -------------- What is sent : \r\n");
        for (int i=0; i<2; i++) {
            int arrayvalue = cmdData[i];
            cmdvalue = cmdData[i];
            pc.printf(" buff: %d        ASCII: %s\r\n", arrayvalue, cmdvalue.c_str());
        }


        //Test output of serial terminal
        //pc.printf(" -------------- Writing: L,0 to i2c\r\n");

        i2c.start();
        //Send a Read request to PH sensor
        i2c.write(addr, cmdData, 1, true);
        i2c.stop();

        //Wait 1second
        wait(1);

        //After 1second read and store received data to phval array
        pc.printf(" -------------- Reading i2c\r\n");
        i2c.start();
        i2c.read(addr, ezodata, 1, false);
        i2c.stop();

        //Loop through buff array and store to buffer string
        for (int i=0; i<sizeof(ezodata); i++) {
            int arrayval = ezodata[i];
            ezovalue = ezodata[i];
            pc.printf(" buff: %d        ASCII: %s\r\n", arrayval, ezovalue.c_str());
        }

        //wait 2 second before next write/read
        wait(2);

    }
}

and, finally, here's the serial output I have :

-- What is sent : buff: 82 ASCII: R buff: 0 ASCII: -- Reading i2c buff: 0 ASCII: buff: 0 ASCII: buff: 0 ASCII: buff: 0 ASCII: buff: 0 ASCII: buff: 0 ASCII: buff: 0 ASCII: buff: 0 ASCII: buff: 0 ASCII: buff: 0 ASCII:

I assure you that my wiring is correct (SDA to SDA and SCL to SCL).

I also tested the sensor with an arduino uno with the test code provided by the manufacturer of the sensor and everything works well.

My board works perfectly with a BME280 sensor using I2C protocol.

I also tried the program proposed in this thread : https://developer.mbed.org/questions/5242/I-would-like-assistence-with-my-first-i2/

but it doesn't work with my sensor, i get absolutely no response.

Any help is greatly appreciated, thanks !

2 Answers

4 years, 7 months ago.

I have not tested the nrf, but for sure the mbed I2C libs dont want to see the i2c.start() and i2c.stop() before and after the i2c block read or write methods. The block read already includes the start and stop conditions.

The clock freq should be lower as mentioned by Sanjiv. The address 0x63 can not be correct. All mbed I2C slaveaddresses must have the LSB set to 0. Make sure the slave device responds to 3V3 level I2C signals. Note that most Arduinos use 5V. Make sure you have a common ground.

Accepted Answer

Hi Wim,

My nrf51dk have the required pull up resistor already integred on the i2c lines, the ph sensor doesn't.

I did the factory reset on my sensor and the manufacturer assures an i2c adress of 0x63 after the factory reset. I tried both 0x63 and 0x63 << 1 without any sucess.

Also the slave doesn't respond to 3.3v level, I use the 5v available on my board while connected to the pc via USB.

Finally i took out the start() and stop() function and slowed down the 12c speed.

Here's my new code wich still doesn't work :

 
#include "mbed.h"
#include <string>
 
Serial pc(USBTX, USBRX); // tx, rx
I2C i2c(p30, p7); // SDA, SCL
 
 // use one of the two following adress
//const int addr = 0x63;
const int addr = 0x63 << 1;
 
//Variables
char cmdData[1];
char ezodata[10];
string ezovalue;
string cmdvalue;
 
int main()
{
    // frequency = 100khz
    i2c.frequency(100000);
 
    pc.printf("\n -------------- Clearing ezodata \r\n");
    for (int i=0; i<sizeof(ezodata); i++) {
        ezodata[i] = 0;
        int arrayval = ezodata[i];
        ezovalue = ezodata[i];
        pc.printf(" buff: %d        ASCII: %s\r\n", arrayval, ezovalue.c_str());
    }
 
    while(1) {
 
        cmdData[0] = 'R'; // command to ask for a ph reading
 
        pc.printf("\n -------------- What is sent : \r\n");
        for (int i=0; i<2; i++) {
            int arrayvalue = cmdData[i];
            cmdvalue = cmdData[i];
            pc.printf(" buff: %d        ASCII: %s\r\n", arrayvalue, cmdvalue.c_str());
        }
 
 
        //Test output of serial terminal
        pc.printf(" -------------- Writing: R to i2c\r\n");
 
        //Send a Read request to PH sensor
        i2c.write(addr, cmdData, 1, true);
 
        //Wait 1second
        wait(1);
 
        //After 1second read and store received data to phval array
        pc.printf(" -------------- Reading i2c\r\n");
        i2c.start();
        i2c.read(addr, ezodata, 1, false);
        i2c.stop();
 
        //Loop through buff array and store to buffer string
        for (int i=0; i<sizeof(ezodata); i++) {
            int arrayval = ezodata[i];
            ezovalue = ezodata[i];
            pc.printf(" buff: %d        ASCII: %s\r\n", arrayval, ezovalue.c_str());
        }
 
        //wait 2 second before next write/read
        wait(2);
 
    }
}

Thanks !

posted by Louis-Philippe Gauthier 02 Mar 2017

According to the EZO datasheet you should probably not use a repeated start for reading. Modify line 47

i2c.write(addr, cmdData, 1, false);

Get rid of the start/stop in lines 54 and 56 as well.

Are you sure the EZO is in I2C mode (the led should be Blue).

According to the datasheet the EZO Vcc and I2C level should be at same voltage. I dont see a datasheet for the nrf kit but assuming it has I2C pullups they will be at 3V3 level so the supplyvoltage for the EZO should also be 3V3. Did you measure the SDA/SCL levels with the EZO removed and the nRF idle/reset. Are they 3V3.

You read only one byte from the EZO. That should be value 1 when the command was recognized. What do you get when printing the ezodata array values.

posted by Wim Huiskamp 02 Mar 2017

Hi Wim,

Good job, you found the problem !

"According to the datasheet the EZO Vcc and I2C level should be at same voltage."

That was my problem, I was powering the chip with 5V and the I2C was on 3V3.

I also took out the last i2c.start() and i2c.stop() and changed the repeated start reading.

Can I ask you where you found the information about the i2c needing to be on the same voltage as the supply in the datasheet ? Thanks again !

Here's the final code wich is working :

 
#include "mbed.h"
#include <string>
 
Serial pc(USBTX, USBRX); // tx, rx
I2C i2c(p30, p7); // SDA, SCL
 
 //adress
const int addr = 0x63 << 1;
 
//Variables
char cmdData[1];
char ezodata[10];
string ezovalue;
string cmdvalue;
 
int main()
{
    // frequency = 100khz
    i2c.frequency(100000);
 
    pc.printf("\n -------------- Clearing ezodata \r\n");
    for (int i=0; i<sizeof(ezodata); i++) {
        ezodata[i] = 0;
        int arrayval = ezodata[i];
        ezovalue = ezodata[i];
        pc.printf(" buff: %d        ASCII: %s\r\n", arrayval, ezovalue.c_str());
    }
 
    while(1) {
 
        cmdData[0] = 'R'; // command to ask for a ph reading
 
        pc.printf("\n -------------- What is sent : \r\n");
        for (int i=0; i<2; i++) {
            int arrayvalue = cmdData[i];
            cmdvalue = cmdData[i];
            pc.printf(" buff: %d        ASCII: %s\r\n", arrayvalue, cmdvalue.c_str());
        }
 
 
        //Test output of serial terminal
        pc.printf(" -------------- Writing: R to i2c\r\n");
 
        //Send a Read request to PH sensor
        i2c.write(addr, cmdData, 1, false);
 
        //Wait 1second
        wait(1);
 
        //After 1second read and store received data to phval array
        pc.printf(" -------------- Reading i2c\r\n");
        i2c.read(addr, ezodata, 10, false);
 
        //Loop through buff array and store to buffer string
        for (int i=0; i<sizeof(ezodata); i++) {
            int arrayval = ezodata[i];
            ezovalue = ezodata[i];
            pc.printf(" buff: %d        ASCII: %s\r\n", arrayval, ezovalue.c_str());
        }
 
        //wait 2 second before next write/read
        wait(2);
 
    }
}
posted by Louis-Philippe Gauthier 03 Mar 2017
4 years, 7 months ago.

HI. Do you have the required pull up resistors for the i2c lines? Also the i2c speed is too fast in your code. The module supports 400khz as a max but your code is set to 2 Mhz. Slow it down to 100khz and try again. If it fails, then use 0x63 for the i2c address and try again. The i2c pull ups are required.

Update:

Lines 54 and 56 of the new code should be removed as well.

Hello Sanjiv,

thank you for your input, please go see the comment I posted to Wim's reply for the answer to your questions !

posted by Louis-Philippe Gauthier 02 Mar 2017