fablabbcn / smartcitizen-kit-20

Smart Citizen Kit 2.0 hardware and firmware
https://smartcitizen.me
GNU General Public License v3.0
37 stars 9 forks source link

Usage of Wire library. #10

Open Koepel opened 6 years ago

Koepel commented 6 years ago

In the file "smartcitizen-kit-20/sam/src/SckAux.cpp", in the function getReading(), there is a line if (auxWire.available()<=2). However, the number of available bytes is never more that the number of bytes that was requested by Wire.requestFrom(). In case of an error, the Wire.available() might return zero. That if-statement is always true.

Why is there is delay(1) after the Wire.requestFrom() ?

I have written about common mistakes and I have an alternative explanation of the Wire functions. Perhaps that can be useful.

On 5 november 2018 I took a closer look at the file:

bryn51 commented 2 years ago

In the file "smartcitizen-kit-20/sam/src/SckAux.cpp", in the function getReading(), there is a line if (auxWire.available()<=2). However, the number of available bytes is never more that the number of bytes that was requested by Wire.requestFrom(). In case of an error, the Wire.available() might return zero. That if-statement is always true.

Why is there is delay(1) after the Wire.requestFrom() ?

I have written about common mistakes and I have an alternative explanation of the Wire functions. Perhaps that can be useful.

On 5 november 2018 I took a closer look at the file:

  • All the timeouts with millis() after a Wire.requestFrom() can be removed.
  • The .endTransmission() after a .requestFrom() can be removed.
  • The sendCommand() function has the wrong sequence of the Wire library functions.

Hi @Koepel

Your article I found very illuminating. I am currently writing code for SmartCitizen station; and having an amount of trouble with the Aux I2C Bus. I have 9 devices connected to that bus; and found quickly that it would not work; for reasons that are hard to establish but surmised to be the fact that the sensors have disparate values of Pullup resistors ranging from 2.7 KOhms to 48 KOhms. I also calculated the I2C signal current and found that it would exceed to specified maximum.

The manufacturers provide no easy way to remove or replace the pullup resistors to bring some sort of order to the chaos;. I came across a possible solution in the form of a TCA 9458A I2C Multiplex board (made by Seeed).

In deploying this unit; each device is connected to its own channel; and code is arranged to enable that channel when the Data Board wishes to take a reading. What I found is that the Mux appears to 'lock up' from time to time; and occasionally seems to require a power cycle to get it to communicate again.

I am able to control the mux during start-up; allowing me to build a map of devices connected to each channel. I turn on one channel at a time and then go through an address discovery routine. It generally finds all of the attached devices (but sometimes misses one); But later; when readings are being taken; is when 'lockups' occur. They appear non-deterministic (random).

I am looking at the call to auxWire.requestFrom(deviceAddress, ...) and wondering whether I need to tell each remote device to cease transmission using Wire.requestFrom(deviceaddress, numbytes, true); I am thinking that possibly one of the devices is handing onto the bus trying to retransmit...

I surmised that possibly the MUX device was unhappy with being asked to rapidly switch channels almost continuously. I have taken measures to try to minimise channel switching; but the problem persists.

If you still have an interest in this general topic; and have a mind to share a little; I wonder if you can shed some further light on this (use of an I2C mux for this purpose).

Koepel commented 2 years ago

Most I2C multiplexers connect the main I2C bus SDA to the (sub) I2C bus SDA1 with a mosfet. That mosfet acts like a switch between SDA and SDA1 and is only turned on for the low level. That means you have to combine the pullup of SDA together with the pullup of SDA1 to calculate the total pullup. The same for SCL, and that for each of the eight (sub) I2C buses. You may not remove the pullup of SDA and SCL because you need those to communicate with the I2C multiplexer itself. It is possible to measure the sink current in the circuit. In your project you can set the MUX to one of its channels and then do nothing in the sketch. Then you can measure the sink current.

The I2C bus is not fault tolerant. Your I2C bus is not okay if it fails just once. The I2C bus was not designed to go through wires. The Grove connector by Seeed is wrong, because that causes crosstalk between SDA and SCL. If your wires are together, then please split the wires.

The GND wire is just as important as SDA and SCL. If that GND wire caries the return current of a motor, then the I2C bus will never be reliable.

You can also ask this on the forum.arduino.cc. Show a photo, give links to each module, tell which Arduino board is used, draw a schematic (with a pen on paper is okay) with all the lengths, and so on.

Do you know that a timeout was added for the I2C bus for the Arduino Uno (for the AVR family boards). That might help to continue the sketch.