pasko-zh / brzo_i2c

Brzo I2C is a fast I2C Implementation written in Assembly for the esp8266
GNU General Public License v3.0
244 stars 47 forks source link

AM2320 sensor not found #33

Closed v-a-d-e-r closed 5 years ago

v-a-d-e-r commented 5 years ago

Hi. With wire library the sensor is found.

pasko-zh commented 5 years ago

Well vader ... your thoughts are strong, very strong and poweful, but you still need a tray 😄 i.e. you would have to show me your code, otherwise I could only think what you might are doing...

v-a-d-e-r commented 5 years ago

Well, I was changing the orig. wire library with yours in ESPeasy. There is a scan function which looks like this: for (address = 1; address <= 127; address++ ) { Wire.beginTransmission(address); error = Wire.endTransmission(); if (error == 0) ...bla bla....

with this: for (address = 1; address <= 127; address++ ) { brzo_i2c_start_transaction(address, 100); brzo_i2c_ACK_polling(1000); error = brzo_i2c_end_transaction(); if (error == 0) ...bla bla....

The orig. code works and find all sensors, yours find all, except the AM2320. For what reason ever.... :-/

pasko-zh commented 5 years ago

I guess it is some timing issue... probably the AM2320 is not 100% within the i2c spec (brzo_i2c follows them very strictly). I will order one and do some checks with the scope.

v-a-d-e-r commented 5 years ago

From the data sheet:

Step one: Wake Sensor In order to reduce the humidity sensor errors caused by self-heating, the sensor in a non-working state, dormant, so to read the sensor must wake sensor to transmit commands to read and write, otherwise the sensor will not respond. It should be noted that, in the wake sensor, I2C address is sent, the sensor does not respond to ACK, but the host must send back an ACK clock verify that the ninth SCL clock signal. Wake sensor operation is following instructions: After the host sends a start signal is applied to the starting address, wait for sometime (waiting time of at least 800 μs, the maximum 3ms; such as host hardware I2C, you do not need to wait for the hardware I2C will automatically wait), and then sends a stop signal. Namely: the starting signal +0xB8 + wait (> 800us) + stop signal timing diagram shown in Figure 15....

Maybe the >800µs is the problem...???

pasko-zh commented 5 years ago

Well, I've already tried to go through this chinglish datasheet... just horrible :-/ Fig 15 looks like i2c clock stretching, but it isn't, since it is supposed to occur before the 9th clock cycle and not after...

Btw, I just saw that you are using only brzo_i2c_ACK_polling(.), you should only use this it if you have a slave needing it, e.g., EEPROMS. Just use brzo_i2c_write(.). Maybe to wake-up the device you need to have two complete write transactions.

But with this kind of datasheet and without a scope it's shooting in the dark...

v-a-d-e-r commented 5 years ago

Yes, the datasheet is a bit scary. They are talking about an I2C address of 0xB8, but it is 0x5C. :-/ Ok, I'll try with brzo_i2c_write(.) ....

v-a-d-e-r commented 5 years ago

Hi. Why is this not working? brzo_i2c_start_transaction(address, 100); error = brzo_i2c_end_transaction(); only this... brzo_i2c_start_transaction(address, 100); brzo_i2c_ACK_polling(1000); error = brzo_i2c_end_transaction();

You wrote, that brzo_i2c_ACK_polling should normally not be used. So what I'm doing wrong?

BTW: Did you get the sensor?

pasko-zh commented 5 years ago

The sensors are on their way from China to Switzerland, as I said I will then check with my scope what is going on.

Hansen-db commented 5 years ago

I had the same problem with AM2320, but solved it by adding another pair of begindTransmission / endTransmission. It seems that this solution has also been discussed at https://forum.arduino.cc/index.php?topic=399437.15

My solution: Wire.beginTransmission(_addr); delayMicroseconds(900); //>0.8ms Wire.endTransmission(); // The AM2320 is now awake Wire.beginTransmission(_addr); // line added as a hack Wire.endTransmission(); // line added as a hack

Maybe I should add, that some AM2320 have been running on some boards without problems. So I'm convinced it is a timing-issue combined with AM2320 production spread.

pasko-zh commented 5 years ago

In short: AM2320 wake-up sequence is not exactly following i2c standard, hence it is not compatible with brzo_i2c

In details Using Adafruit's library, the AM2320 wake-up sequence works as follows

ds1z_quickprint2

After that i2c communication works in a normal way. Note the 10 msec delay after wake-up sequence, according to this line here

ds1z_quickprint7

Then, the second sequence in details (the small spikes are so-called ACK spikes)

ds1z_quickprint8

So in the wake-up sequence, the device is not acknowledging the slave address, i.e. the i2c master gets an NACK. And then, it is expected by the AM2320 that the master pulls SDA low. The AM2320 will then stretch the clock as long as it is waking up. Above you can see that it stretches the clock after 9th cycle for about 75 usec.

According to i2c standard, if an i2c master does not receive an ACK, it means that the slave with given address is not present on the i2c bus. Therefore, the master will not transfer any bytes to this slave (address)—simply because this slave was not responding. This is exaclty how brzo_i2c behaves: If after transmitting the slave address there is no ACK (i.e. NACK), it will not send any more bytes and/or does not check for clock stretching.

The only way to make this sensor working correctly with brzo_i2c, is to write a specifig wake-up code...

v-a-d-e-r commented 5 years ago

Ah, ok. Thanks for clearing this. But I kick the crappy sensor into trash, that goes by far faster than writing a special code for it... ;-)