Skip to content

ESP8266 I2C K30 CO2 sensor problem [Included Oscilloscope Images] #3088

New issue

Have a question about this project? No Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “No Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? No Sign in to your account

Closed
cbrum11 opened this issue Mar 26, 2017 · 2 comments
Closed

ESP8266 I2C K30 CO2 sensor problem [Included Oscilloscope Images] #3088

cbrum11 opened this issue Mar 26, 2017 · 2 comments

Comments

@cbrum11
Copy link

cbrum11 commented Mar 26, 2017

EDIT: # THIS IS SOLVED. I'm leaving everything here because people might find it entertaining that I spent so much time on something that was such a simple fix. I simply had my wiring wrong. Skip to the third post to see the correct wiring for the K30 sensor and I2C. Co2Meter customer service was really great, I highly recommend them.

Basic Info

Trying to connect to CO2 Sensor K30 via I2C but cannot even get I2C scanner code to find the device address.

Sensor Webpage HERE --> https://www.co2meter.com/products/k-30-co2-sensor-module

Sensor Data Sheet HERE --> http://co2meters.com/Documentation/Datasheets/DS30-01%20-%20K30.pdf

Sensor I2C Application Note HERE --> http://co2meters.com/Documentation/Other/SenseAirCommGuide.zip

Example Arduino I2C Code/Application Note provided by the company that does not work HERE ---> http://cdn.shopify.com/s/files/1/0019/5952/files/Senseair-Arduino.pdf?1264294173

See "Description" section below for everything I have tried...

Hardware

Hardware: Wemos D1
Core Version: ESP8266 Arduino Core Version: 2.0.0_16_08_09 [from esp8266/tools/sdk/version file]
Arduino IDE Version: 1.6.9

Description

No matter what I try I cannot get the K30 sensor to return it's I2C address to the WEMOS. I'm not sure if this is an I2C scanner code issue or an issue with the I2C timing/pulses. I have also tried an Arduino Uno with absolutely no luck.

I would like to actually take CO2 Measurements of course, but the first step is to simply get the device to acknowledge a connection.

The below are images I used trying different combinations of connections and resistor values to pull-up the I2C lines. My hope is that someone will be able to see the problem from these images. The K30 Sensor contains a pin called DVCC that is meant to be used to set the logic level of the I2C side of things.

This pin is supposed to be completely separate from the power provided to the sensor and allow you to work with either 3.3V or 5V logic. Just for clarification, my pull-up resistors go from the I2C lines to this DVCC pin.

I am pretty new to electronics (this is my first time using an Oscilloscope), so please let me know if I can do any more tests or provide any more screenshots that would help diagnose this issue.

All tests were done with the following consistent connections.

  1. Laptop ---> Powering Wemos
  2. External Power Supply set to 9V ---> Powering K30 Sensor
  3. Wemos D1[SCL] --> Sensor SCL
  4. Wemos D2[SDA] --> Sensor SDA
  5. COMMON GROUND

***Volt/div of oscilloscope set at 1.5Volts for all tests using 1x probe.

Each test was then done by varying the connections listed above each image.

TEST1

Wemos 5V Pin ---> DVCC of K30 Pin
I2C Resistor Value ---> NO RESISTOR USED

w5v0

TEST 2

Wemos 5V Pin ---> DVCC of K30 Pin
I2C Resistor Value ---> 10K ohm

w510

TEST 3

Wemos 5V Pin ---> DVCC of K30 Pin
I2C Resistor Value ---> 4.7 K ohm

w547

TEST 4

Wemos 5V Pin ---> DVCC of K30 Pin
I2C Resistor Value ---> 330 ohm

w5v330

TEST 5

Wemos 3.3V Pin ---> DVCC of K30 Pin
I2C Resistor Value ---> NO RESISTOR USED

w3v0

TEST 6

Wemos 3.3V Pin ---> DVCC of K30 Pin
I2C Resistor Value ---> 10 K Ohm

w310

TEST 7

Wemos 3.3V Pin ---> DVCC of K30 Pin
I2C Resistor Value ---> 4.7 K Ohm

w347

TEST 8

Wemos 3.3V Pin ---> DVCC of K30 Pin
I2C Resistor Value ---> 330 Ohm

w3v330

TEST 9

DVCC of K30 SENSOR NOT CONNECTED TO ANYTHING
I2C Resistor Value ---> NO RESISTOR USED

w00

Conclusions

Of the resistor values tested (No resistor, 10Kohm, 4.7Kohm, and 330ohm) the 330ohm resistor appears to make the most square wave. This also appears to be independent of whether 3V or 5V logic is applied to the DVCC pin on the sensor. Even though these waves appear "the most square" could someone please help me understand how to tell if they are within I2C specs?

Also, although I don't know much about I2C, the difference in wave heights seems very strange to me. I assumed that both lines should operate over about the same range? Is this not correct?

For example, (unless I'm reading something wrong) considering that the volts/div are 1.5V, if you look at TEST 4 :

  1. The top, yellow, channel 1 line [SCL] corresponds to a voltage change of about 2.1 volts
  2. The bottom, blue, channel 2 line [SDA] corresponds to a voltage change of about 3.6 volts

Is this what's supposed to happen? What gives!?

In addition to the above, on all the tests, the yellow, SCL line appears to be floating way above zero volts when pulled down? I'm assuming this isn't good either? Once again... What gives!?

Finally, I couldn't get the entire transmission to fit in 1 screen capture, so I mashed 3 screen captures together to make an image of what was sent when I ran the below code. I'm not sure yet how to read it, but perhaps someone can derive my communication problem from reading it. I actually not really sure it's the entire communication. I set my scope to trigger on the falling edge and to "single" and this is what it gave me. I'm actually not sure why it stops recording? If someone could clear that up it would be fantastic. Like I said, I'm pretty new to all this. In the meantime, I'm going to try and research I2C myself and see if I can't figure out what's going on.

TEST 10 The Beginning of Scanner Transmission Run at 3.3V with 330Ohms I2C Resistor

123

**Side Note: The sensor datasheet claims this sensor has internal resistors already associated with the I2C lines and, if I understand correctly, seems to make the claim that external resistors aren't necessary. I think these tests show this to be absolutely false? Any clarification is appreciated.

Any and all help is greatly appreciated. I've spent a few hours putting all this together, so I sincerely hopes the community find it helpful and that the eventual solution helps many other people.

-Chase

I2C Scanner Code Used

//  I2C Scanner from Arduino.cc
//  Attribution to Krodal, Nick Gammon, Anonymous
 
#include <Wire.h>
 
void setup()
{
  Wire.begin();
 
  Serial.begin(9600);
  Serial.println("\nI2C Scanner");
}
 
void loop()
{
  byte error, address;
  int nDevices;
 
  Serial.println("Scanning...");
 
  nDevices = 0;
  for(address = 1; address <= 127; address++)
  {
    // The i2c_scanner uses the return value of
    // Wire.endTransmission to see if
    // a device acknowledged the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
 
    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");
 
      nDevices++;
    }
    else if (error==4)
    {
      Serial.print("Unknown error at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");
 
  delay(5000);           // wait 5 seconds for next scan
}
@cbrum11 cbrum11 changed the title ESP8266 I2C K30 CO2 sensor problem [Included Oscoilliscope Images] ESP8266 I2C K30 CO2 sensor problem [Included Osilloscope Images] Mar 26, 2017
@cbrum11 cbrum11 changed the title ESP8266 I2C K30 CO2 sensor problem [Included Osilloscope Images] ESP8266 I2C K30 CO2 sensor problem [Included Oscilloscope Images] Mar 26, 2017
@cbrum11
Copy link
Author

cbrum11 commented Mar 27, 2017

Update:

Today I tried the I2C Scanner code with an Arduino Uno in case the issue was with the WEMOS. Sadly, I have the same issue. The sensor does not respond to any address.

I decided to dig into the entire scan/scope reading and find the two addresses that the company datasheet claims the sensor will respond to [0x68 as default and 0x7F].

Here is the result of the scan for both of those addresses [click to enlarge]:

not acknowledged

With my limited I2C experience, it seems like the I2C code is working perfectly and the sensor simply is not sending an acknowledge bit [the 9th bit] for any address.

But wait... as I'm writing this I just realized there are 9 bits AND THEN what looks like the Acknowledge bit:

what the heck is this bit

Am I crazy here? Can someone please explain if I've got something completely wrong?

# EDIT: The above is absolutely wrong. I completely ignored the start and stop conditions. The acknowledge bit IS the 9th bit and the long looking change after it is the stop condition for one transmission and the start condition for the next. Leaving it all here in case someone finds any of this useful

Finally, here's the datasheet tables that I'm trying to work from. The company even provides a very clear example (to bad it doesn't work)...

Complete Sensor I2C Datasheet --> http://co2meters.com/Documentation/Other/SenseAirCommGuide.zip

request

response

example

One very interesting point to note is that I found some I2C code below from the company that seems to contradict the above example that also comes from their documentation. If you look specifically at the Wire.begin(address), in the below code they assign an address of 0x68 for the sensor. However, this is only a 7 bit address and the above example states that we should be sending 8 bits on first connect?

In the above example, they even state that instead of using 0x68, use 0xD0 (which is 0x68 shifted over 1 bit, sending the 7 bit address and a 0 as the write bit)

0x68=1101000
vs.
0xD0=11010000

I tried both with the below code and neither worked. All opinions welcome ;(

// CO2 Meter K-series Example Interface
// Revised by Marv Kausch, 7/2016 at CO2 Meter <co2meter.com>
// Talks via I2C to K30/K22/K33/Logger sensors and displays CO2 values
// 12/31/09
#include <Wire.h>
// We will be using the I2C hardware interface on the Arduino in
// combination with the built-in Wire library to interface.
// Arduino analog input 5 - I2C SCL
// Arduino analog input 4 - I2C SDA
/*
  In this example we will do a basic read of the CO2 value and checksum verification.
  For more advanced applications please see the I2C Comm guide.
*/
int co2Addr = 0x68;
// This is the default address of the CO2 sensor, 7bits shifted left.
void setup() {
  Serial.begin(9600);
  Wire.begin ();
  pinMode(13, OUTPUT); // address of the Arduino LED indicator
  Serial.println("Application Note AN-102: Interface Arduino to K-30");
}
///////////////////////////////////////////////////////////////////
// Function : int readCO2()
// Returns : CO2 Value upon success, 0 upon checksum failure
// Assumes : - Wire library has been imported successfully.
// - LED is connected to IO pin 13
// - CO2 sensor address is defined in co2_addr
///////////////////////////////////////////////////////////////////
int readCO2()
{
  int co2_value = 0;  // We will store the CO2 value inside this variable.

  digitalWrite(13, HIGH);  // turn on LED
  // On most Arduino platforms this pin is used as an indicator light.

  //////////////////////////
  /* Begin Write Sequence */
  //////////////////////////

  Wire.beginTransmission(co2Addr); //<----***SHOULDN"T THIS BE 0xD0!!!??? need to send the 
                                   // 7 bit address AND a read/write bit
                                   //0x68 = 1101000
                                   //0xD0 = 11010000
                                   //It shifts it over.... tried this but it still didn't
                                   //respond ;(
  Wire.write(0x22);
  Wire.write(0x00);
  Wire.write(0x08);
  Wire.write(0x2A);

  Wire.endTransmission();

  /////////////////////////
  /* End Write Sequence. */
  /////////////////////////

  /*
    We wait 10ms for the sensor to process our command.
    The sensors's primary duties are to accurately
    measure CO2 values. Waiting 10ms will ensure the
    data is properly written to RAM

  */

  delay(10);

  /////////////////////////
  /* Begin Read Sequence */
  /////////////////////////

  /*
    Since we requested 2 bytes from the sensor we must
    read in 4 bytes. This includes the payload, checksum,
    and command status byte.

  */

  Wire.requestFrom(co2Addr, 4);

  byte i = 0;
  byte buffer[4] = {0, 0, 0, 0};

  /*
    Wire.available() is not nessessary. Implementation is obscure but we leave
    it in here for portability and to future proof our code
  */
  while (Wire.available())
  {
    buffer[i] = Wire.read();
    i++;
  }

  ///////////////////////
  /* End Read Sequence */
  ///////////////////////

  /*
    Using some bitwise manipulation we will shift our buffer
    into an integer for general consumption
  */

  co2_value = 0;
  co2_value |= buffer[1] & 0xFF;
  co2_value = co2_value << 8;
  co2_value |= buffer[2] & 0xFF;


  byte sum = 0; //Checksum Byte
  sum = buffer[0] + buffer[1] + buffer[2]; //Byte addition utilizes overflow

  if (sum == buffer[3])
  {
    // Success!
    digitalWrite(13, LOW);
    return co2_value;
  }
  else
  {
    // Failure!
    /*
      Checksum failure can be due to a number of factors,
      fuzzy electrons, sensor busy, etc.
    */

    digitalWrite(13, LOW);
    return 0;
  }
}
void loop() {

  int co2Value = readCO2();
  if (co2Value > 0)
  {
    Serial.print("CO2 Value: ");
    Serial.println(co2Value);
  }
  else
  {
    Serial.println("Checksum failed / Communication failure");
  }
  delay(2000);
}

Please, if you have the time and could give me advice on how to further troubleshoot this it would be GREATLY appreciated. I've basically reached my knowledge ceiling in this area and I'm not sure how to keep troubleshooting?

-Chase

@cbrum11
Copy link
Author

cbrum11 commented Mar 29, 2017

So it turns out that I went way too far down this rabbit hole.

After 30 hours of troubleshooting and speaking to CO2Meter, as embarrassing as it is to say, they kindly showed me that I had my wiring wrong.

The correct wiring is below... I had all the wires one row up ;(

k30

In my defense, there's a lot of pads on this damn sensor. A good lesson... the simplest answer should always be considered first.

I have to say, CO2meter had phenomenal customer service. I highly recommend them. I'm closing this now and will update the above two posts to reflect conclusions here.

Thanks,
Chase

@cbrum11 cbrum11 closed this as completed Mar 29, 2017
No Sign up for free to join this conversation on GitHub. Already have an account? No Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant