I2C with CCS811 basic question

Hello everyone,

I have a question regarding I2C and specifically used for CCS811, but it would apply to all applications.

So I am using the library provided here and I am trying to make my CCS811 on Air Quality click 3 work. The library provides an init() functions which checks the hardware and returns that everything is correct, thus I assume there is communication with the chip.

Since I am fairly new to I2C, I am trying to understand the basics. My aim is to set the measure mode to a value and then read the register to extract the measure mode information and check if it’s correct and if I am using it correctly. I do the following: (also I don’t know how code will appear, let me know how to fix it)

#include “mbed.h”
#include “CCS811.h”
Serial ble(PC_12,PD_2);
I2C i2c(PC_1,PC_0);
CCS811 ccs(i2c,ble);
DigitalOut wake(PB_2);
int main(){

wake=0; //Enable i2c transactions with the chip

ccs.init();//Check hardware and initialise

ccs.setMeasureMode(0x10); //Set measure mode to mode 1

char write[1];
char read[1];

int addr=0xB4; //8-bit slave addres
write[0]=0x01; //measure mode register

while(1){
    i2c.write(addr, write,1);
    i2c.read(addr,read,1);
    
    ble.printf("%x\n",read[0]); //read in HEX and manually convert to binary to check bits 6:4
    wait(1);
}

}

The datasheet states that register 0x01 returns byte and the bits I am interested in are 6:4. When I run this code, even though I should be getting 001 for the specific mode, I get a 0x81 and converting to binary it is 10000001, thus 6:4 is 000.

Am I understanding the I2C correctly or am I doing something fundamentally wrong?
Thank you,
Chris

Hi Chris,

The 0x81 looks like a device ID.
However on first look I see nothing wrong from you but maybe you can try to check if ACKs, by the write and read methods, were returned.

        printf( (i2c.write(addr, write,1))==0 ? "ACK\n" : "NAK\n");

I am not sure but maybe in this library is a mistake. When you check .cpp of the lib what you use and check line 35 and compare it with this .cpp (from this page) on line 67 you will see a different macro.

BR, Jan

Hello Jan,

Thank you very much for the reply, I will try your suggestion regarding the ACKs and get back to you. Also regarding 0x81, yes the init() function checks the device ID and returns success, so I assume I am communicating with the chip on some level.

I have actually tried using the second library you linked to and I couldn’t get meaningful results from that either, however I did not try this test to change the mode and check the bits.

I am starting to think the sensor is faulty so I have ordered a replacement to check. In any case, I will rerun the tests using the second library and see. At least it is good to know that my I2C program should be correct.

Thank you,
Chris

Hi again,

add to I2C basics, I hope it is not problem in this case, usually a common problem is missing or not insufficient resistance for pull-ups of the I2C. Some times are solved by internal on-chip pull-ups, some time some modules already have it, but usually it is need to be solved by the user.

However in the library, what I posted above, is already a method for read the settings.
You can try the code below based on this example but I can not test it because I not have this chip.

#include "mbed.h"
#include "CCS811.h"
 
Serial pc(USBTX, USBRX);
CCS811 ccs811(I2C_SDA, I2C_SCL);
 
uint16_t eco2, tvoc;

 
int main()
{
    ccs811.init();
    //cc811.setMeasureMode(CCS811_MEASUREMENT_MODE1); // It is looking like this not necessary because CCS811_MEASUREMENT_MODE1 mode is set during Init()
    thread_sleep_for (500);
    ccs811.readmeas(); //this return the setting of means
    ccs811.readstatus(); //0x90 reports everything working, 0x98 measurement ready to be used
    thread_sleep_for (500);
 
    while(1) {
        //ccs811.readstatus(); //0x90 reports everything working, 0x98 measurement ready to be used
        thread_sleep_for (1000);
        ccs811.readData(&eco2, &tvoc);
        pc.printf("eCO2 reading :%dppm, TVOC reading :%dppb\r\n", eco2, tvoc);
    }
}

BR, Jan

Hello,

I am finally getting somewhere but I am not using libraries any more and writing it from scratch. I was able to read the chip ID correctly!

I have another quite basic question. Say slave address 0xEC and register address I am trying to reach is 0x72 and I want to set that to 0x1 would I do this:

char write[2];
write[0]=0x72;
write[1]=0x1;
i2c.write(0xEC,write,2);

So lowest byte is the register address and highest byte is the command? I am trying to understand this from the MBed I2C example but they don’t state which is the byte register and which is the command…

Thank you,
Chris

Hi,

it looks ok and it depends on the application but a model of what you need to hold in this aplication, you can found in the datasheet, page 13.

BR, Jan

1 Like

Great thank you so much, it all makes sense now and I have communication with the chip.

You have been far more helpful than the documentation I must say, cheers!

Chris

You are welcome
I’m glad you achieved what you wanted.
Good luck with your project

Jan

Good morning,

One last question and I think I am set. With reference to page 22 of the datasheet, the firmware register is two bytes, byte0 and byte1. In which order are bytes saved in the array?

char wE[1];
wE[0]=0x24;
char rE[2];

i2c.write(addr,wE,1);
i2c.read(addr,rE,2);
pc.printf("Byte0: %x, Byte1: %x\n",rE[0], rE[1]);

Is byte0 in rE[0] and byte byte1 in rE[1]?

Thank you,
Chris

Hello,

I saw your post before edit. Are you sure, you are read a right register?
You wrote about errors but the error register has only one byte on the address 0xE0. Your address register is for firmware version, according to page 22 of datasheet.

However, I do not know, but logic say me yes, you will found byte0 in rE[0] and byte1 in rE[1].

BR, Jan

Hello,

Yes I realised I was using the wrong register. Since the error is one byte I get it to be 0x00 correctly, but I was still wondering about the order that data is saved in the array.

Great thanks once again :smiley:

Hello,

A month later I was able to test all sensors and all of them work correctly. I have one more question if you could help me.

I am using an STM32L496 LQFP64 processor and I have designed a PCB which has 4 sensors and each sensor uses one of the four I2C buses to make it simpler (or so I thought…) When I compile my program, I use the NUCLEO-L476RG as a target board, because their processor is 64 pin as well.

On my new PCB I am using pins PB10/PB11 (I2C2 or I2C4) and pins PB13/PB14 (I2C4). My intentions are for PB10/11 to be I2C2 bus and PB13/14 to be I2C4 bus. However the NUCLEO-L476RG has both pairs of pins as I2C2 bus labelled on their schematic. And indeed when I upload my program with both sensors on on the our pins, I get no readings, while if I remove one sensor, the other works fine.

My question is, how can I explicitly make PB10/11 pair work on I2C2 so that I2C4 is free for the PB13/14?

Thank you,
Chris

Hi Chris,

  • L496 has 4x I2C
  • L476 has only 3x I2C.

That is more like a Custom target but I have no experience with it.
Maybe you can ask @hudakz (Hello), if he can show you the right way. I think he is much more experienced about that.

BR, Jan

Hello,

Thank you for your reply once again! I was looking into a board which shares exactly the same processor but didn’t find one yet.

Also I was reading that I might be able to change the pin assignment for the board in the PeripheralPins.c file. To do that, I am trying ti import mbed-dev library but that is taking forever and return with errors constantly. I will try again tomorrow, thank you for your help!

Edit: I am now wondering if I use a target such as Disco-L496 even though it is a 169-pin processor, it might allow me to reach the I2C buses on the pins that I want them. Will experiment tomorrow.

Chris

OK, after a few days trying to upload that mbed-dev library, apparently it is too big and the compiler times out.

I found a work around by using the MBed Studio, you have access to the Targets and can change the PeripheralPins.c to use two different I2C buses. The only “problem” with that is the navigation to the .bin file

I am not sure what you mean but this will help you?

Thank you, yes I found it after a bit of exploring! It is all working fine now, but they should really fix that mbed-dev file so that it works on the online compiler…I spent too long trying to find a workaround

If you think Mbed 2, I was able to import it from link what is in this post.
From this one, I have also timeout.

BR, Jan