fivdi / i2c-bus

I2C serial bus access with Node.js
MIT License
348 stars 57 forks source link

wrong read after a while #45

Closed farfromrefug closed 6 years ago

farfromrefug commented 6 years ago

Hi @fivdi We found an issue with >=2.0.0 (just tested with 3.0.0). Quite hard to explain. I have a sensor on my i2c (edison).

export class HTMeter extends i2cMeter {
    getAddress() { return 0x27 }
    constructor(opts?) {
        super(opts);
    }
    readData = (): Promise<{ humidity: number, temperature: number }> => {
        return new Promise((resolve, reject) => {
            let data = new Buffer(4);
            // console.log('HTMeter', 'readData', this.i2c._busNumber, this.address, 0x11, 4);
            try {
                this.i2c.i2cWriteSync(this.address, 0xA0, 2, new Buffer([0x00, 0x00]));
            } catch (e) {
            }
            var delay = 36.65;
            setTimeout(() => {
                try {
                    this.i2c.i2cWriteSync(this.address, 0x80, 2, new Buffer([0x00, 0x00]));
                } catch (e) {
                }
                this.i2c.readI2cBlock(this.address, 0x11, 4, data, function (err, bytesRead, data) {
                    if (err) {
                        reject(err);
                    } else {
                        // First two bytes for humidity
                        // In the range ( 2^14 - 1 )
                        let raw_humidity = ((data[0] & 0x3f) << 8) | data[1];
                        let humidity = raw_humidity / 16382;
                        // Second two bytes for temperature
                        // In the range ( 2^14 - 1 )
                        // Multiply by 165 and subtract 40
                        // Because that is what the documentation says
                        let raw_temperature = ((data[2] << 8) | data[3]) >> 2;
                        let temperature = (raw_temperature / 16382) * 165 - 40;
                        resolve({
                            temperature: Math.round(temperature * 1000) / 1000,
                            humidity: Math.round(humidity * 1000) / 1000
                        });
                    }
                });
            }, delay);
        });
    }
}

the first read value are wrong. If i refresh quickly then the value gets right. If i keep on in continuous, it works perfectly. But as soon as i pause and wait to read a new value, it gets wrong again

So: -read :wrong -read:good -read:good ...

And -read: wrong

This does not happen with 1.2.5

EDIT: to help i got the buffer when wrong and good. They represent the same sensor data wrong: <Buffer 7f ff ff fd> good: <Buffer 53 56 5f 75>

fivdi commented 6 years ago

There are two potential exceptions being ignored in the code. Can you changes both occurrences of

                } catch (e) {
                }

to:

                } catch (e) {
                  console.log(e.stack);
                }

to see if there are exceptions please?

fivdi commented 6 years ago

Exception handling changed a lot with i2c-bus@2.0.0.

fivdi commented 6 years ago

One additional question. Are you 100% sure that readData in the above code is not being called a second time before the first call has completed? Calling readData a second time before the first call has completed is likely to mess things up.

farfromrefug commented 6 years ago

@fivdi i will add the error log and report. About the 2 parallels calls, it can happen in our lib, but that was not the case for sure here.

PS: thanks for your really fast answers!

fivdi commented 6 years ago

What type of sensor is it?

farfromrefug commented 6 years ago

It's the HIH6130: https://www.sparkfun.com/products/11295

fivdi commented 6 years ago

I don't have a HIH6130.

farfromrefug commented 6 years ago

@fivdi Yes i get you might not have one. I did not get the chance to test it again yesterday. Will do and report more info here next week. BTW we had the exact same behavior on around 10 installations (different platform, different sensor).

fivdi commented 6 years ago

Various documents related to the HIH6130 can be found at https://sensing.honeywell.com/HIH6130-021-001-humidity-sensors.

If I'm not mistaken the following two technical notes describe I2C communication with a HIH6130: https://sensing.honeywell.com/i2c-comms-humidicon-tn-009061-2-en-final-07jun12.pdf https://sensing.honeywell.com/command-mode-humidicon-tn-009062-3-en-final-07jun12.pdf

The source code posted above doesn't appear to be doing what the technical notes describe as being necessary to read temperature and humidity data. For example, section "2.3 Humidity and Temperature Measurement Request" in the first document linked to describes how to make a humidity and temperature request. Where is this happening in the code posted above?

To read the humidity and temperature the code reads four bytes from register 0x11 which according to the second document is EEPROM. Is this really the correct thing to do?

Why does the above code switch to command mode and after a short timeout back to normal mode every time readData is called?

According to Table 1 on the second page of the second document linked to switching to normal mode takes 42.5 ms to complete. The code posted above doesn't wait for it to complete.

fivdi commented 6 years ago

@farfromrefug were you able to make any progress here?

farfromrefug commented 6 years ago

@fivdi sorry for not answering.I did not have time to really work on this. Will try today. Now about the code. It's base on this: https://github.com/rwaldron/johnny-five/blob/59bcf34c322d8042f3d5cdaafdfdf43efacaf412/lib/imu.js#L210

That code works really well. We have around 50 devices using that code and millions of measurements made.

Though i am not saying there is not a bug in my code! I will try to look at it more this afternoon.

Thanks again for looking at this.

fivdi commented 6 years ago

I'd recommend doing things as suggested in the data sheet.

In the code posted above there 0x11:

this.i2c.readI2cBlock(this.address, 0x11, 4, data, function (err, bytesRead, data)

Where is the 0x11 in the J5 code?

farfromrefug commented 6 years ago

@fivdi exactly ! I asked myself the same thing. I am actually doing it myself. It's in the code i shared.

I finally got the time to test again with the logs. i get that

error writing in HTMeter Error: Invalid buffer 2

maybe the function signature changed. Currently looking at it...

fivdi commented 6 years ago

Why is 0x11 in the code you shared in the OP? Why was it ever needed?

Signatures have not changed in i2c-bus.

fivdi commented 6 years ago

Please take a look at the documentation. It's bus.i2cWriteSync(addr, length, buffer). The code in the OP doesn't call i2cWriteSync correctly. It has the following:

this.i2c.i2cWriteSync(this.address, 0xA0, 2, new Buffer([0x00, 0x00]));

and the following:

this.i2c.i2cWriteSync(this.address, 0x80, 2, new Buffer([0x00, 0x00]));
farfromrefug commented 6 years ago

@fivdi exactly ! I asked myself the same thing. I am actually doing it myself. It's in the code i shared.

I finally got the time to test again with the logs. i get that

error writing in HTMeter Error: Invalid buffer 2

maybe the function signature changed. Currently looking at it...

EDIT: actually i think i found the issue. i was actually always getting that error. But ignoring it before! I was using i2cWriteSync instead of writeBlockSync Now why was it working before and failing now, i have no idea :s

Sorry to have bothered you with this. And thank for helping me find the source of my problem !!!

fivdi commented 6 years ago

@farfromrefug Good to hear that it's working now. To be honest I don't understand why it's working but that's a different issue :smile:

farfromrefug commented 6 years ago

@fivdi ;) Thanks again for your help on this.