Hi,
I am trying to re-use a program written for Arduino UNO but I am facing that the setWireTimeout() function does not work in the DUE model. Any ideas of how to fix/replace that issue?
thanks!
No, sorry.
It is even worse. The Arduino Team puts the main effort on new things. There are a number of problems reported for example with the SAMD (MKR Zero) boards and the I2C bus.
But wait, it gets worse. You should not have bought a Arduino Due. There seems to be no active support for it anymore and it has problems. The hardware of the Due is already a problem because it has pullup resistors of 1k5 or 1k for SDA and SCL. That is to much pullup for many projects.
The Wire.setTimeout()
was added to the AVR branch of boards (Uno, Mega, and so on). It was not a overall wide introduction of a timeout. It does not exist on other boards and there is no fix for it.
The I2C bus is not a fault tolerant bus. You should fix your I2C bus problems before using the Wire.setTimeout()
.
I was waiting for a new sketch without bugs in your previous topic. But instead of fixing problems, you opened a can of spiders when you bought the Due board
I see. Regarding to my previous topic, I applied that fixes but using Due. I realized I no longer need to use setWireTimeout since Due does not get frozen in case of sudden I2C disconnection. Thus, I can control the LED alert easily.
Then the resulting code is the following (for Due)
#include <Wire.h>
#include <Adafruit_BMP280.h>
/* -------------------------------------------------------
| Define barometer sensor BMP280 necessary parameters |
-------------------------------------------------------
PIN configuration:
----------------------
| PIN | SENSOR PIN |
----------------------
| SDA | SDA |*
| SCL | SCL |*
| GND | GND |
----------------------
*/
#define BMP280_ADDRESS (0x76)
Adafruit_BMP280 bmp;
#define LED_PIN 7
/*
* current and previous status (1 active, 0 idle)
*/
uint8_t BARO_CURR = 1;
uint8_t BARO_PREV = 0;
unsigned long currentMillis;
unsigned long previousMillis;
void setup() {
Serial.begin(57600);
//begin BMP_280 connection to interface I2C (0x76 -> BMP280_ADDRESS)
bmp.begin(BMP280_ADDRESS);
//Wire setup
Wire.begin();
//LED setup
pinMode(LED_PIN, OUTPUT);
}
void loop() {
currentMillis = millis();
read_bmp280();
alert_missing_baro();
//delay(250);
}
void read_bmp280() {
float pressure = bmp.readPressure();
float temperature = bmp.readTemperature();
Serial.println(pressure);
Serial.println(temperature);
Serial.println("\n");
}
/*
Check our barometer sensor status and act in consequence
*/
void alert_missing_baro() {
Wire.beginTransmission(0x76);
uint8_t transmission_status = Wire.endTransmission();
//I2C at address 0x76 is active -> LED OFF
if(transmission_status == 0) {
if(!BARO_CURR) { //detecting a reconnection just once
Serial.println("Reconnecting...");
bmp.begin(BMP280_ADDRESS); //restart the transmission of data after a reconnection
BARO_PREV = BARO_CURR;
BARO_CURR = 1;
digitalWrite(LED_PIN, LOW);
}
//Serial.println("SENSOR CONNECTED!\n");
}
//I2C at address 0x76 is idle -> LED ON
else {
if(BARO_CURR) { //detecting a disconnection just once
previousMillis = currentMillis = millis();
BARO_PREV = BARO_CURR;
BARO_CURR = 0;
}
if(currentMillis - previousMillis >= 3000) { //wait 3 seconds until confirm barometer is missing
digitalWrite(LED_PIN, HIGH);
}
//Serial.println("DISCONNECTED!! LED IS ON NOW.\n");
}
}
Regarding to the scenario where I imagine the sensor can be suddenly disconnected, my aim is just being able to handle scenarios where a sensor can suddenly stop giving me the data, recognize it and raise the alert.
About the Due issue, it is good for me to know what you said. I have both Mega and Due and, for my final project (drone), I have to decide which one to use. Seems Due is not really the good one among them.
The Mega is a 5V board with a 5V I2C bus (SDA and SCL are 0V or 5V).
The Due is a 3.3V board with a 3.3V I2C bus (SDA and SCL are 0V or 3.3V).
If your sensors are 3.3V, then a 3.3V board is easier. A I2C level shifter can connect a 3.3V I2C bus to a 5V I2C bus, but that level shifter weakens the I2C bus.
Other options are the Raspberry Pi Pico and the ESP32.
You don't need all those pins, you can always add extra hardware for more pins, such as I2C I/O expanders.
I have a problem with that. Could you clarify in some way that makes technical sense?
If "a level shifter weakens the I2C bus", then the somehow the I2C bus would be "weaker" with the level shifters than without... but it is not measurably weaker in any regard. In fact, it's often stronger with level shifters in place because (at least some) level shifters can drive a lot of devices against a lot of bus capacitance.
In short: Every solution has its pros and cons.
When the voltages match (a 3.3V board with a 3.3V sensor for example) then the noise margin is okay and the pullup resistors determines the impedance of the I2C bus.
When a 5V board connects to a 3.3V sensor and the combination of pullup resistors keep the SDA and SCL near 3.6V, then it will work, but there is no noise margin.
A level shifter brings back the noise margin, that should improve it.
The simple level shifters use mosfets, as in this Sparfun tutorial: Bi-Directional Logic Level Converter Hookup Guide - SparkFun Learn
When the LV side is low, the gate turns on, connecting the HV side to the LV side (the SDA or SCL of the HV and LV side).
When the HV side is low, the internal diode pulls down the LV side, thus enabling the gate which helps to get the LV side even closer to the low level on the HV side.
At low voltages, that internal diode will open the gate less.
A resistor in the signal path of 100Ω is noticeable, but the BSS138 does 6Ω. However, there is also the gate capacitance. I think it is combination of everything in the circuit that influences the signal.
Adafruit has often level shifters on the modules. If those are combined with a extra level shifter for the whole bus, then it might no longer work.
There can be so many things going on. Suppose there are two level shifters in the signal path, dividing the I2C bus into three parts, each with pullup resistors. Maybe a level shifter shifts to the same voltage. Then every I2C device has to pull down the signal of all three parts. I had bad experience with that situation and others on this forum reported that the I2C stopped working with two level shifter in the signal path.
There are chips that sense both sides and when one of the sides is low, then they connect both sides with a mosfet. That's better.
There are also chips that amplify the signal and thus the HV and LV side are separated. Someone on this forum could make it project work with those chips, but I'm afraid that noise will also be amplified.
Sometimes I have to read the datasheet a few times to understand if both sides are simply connected with a mosfet, or if there is a amplifier in between.
For a I2C bus over a longer distance, there are chips that turn the signal into twisted pair signals. A twisted pair for SDA and another twisted pair for SCL. If someone chooses that, then RS-485 is more straightforward.
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.