My project has DS3231 RTC and PCF8575 16bit IO attached to the I2C bus working nicely.
When I add the DS2482 onewire bus master to the I2C bus I find that reads from the RTC and IO are getting corrupted. The Wire (I2C) object is not detecting errors and the DS2482 is reading a small network of temperature sensors nicely.
I have looked at the bus with a scope and the waveforms shapes look good.
The platform is ESP32.
I have implemented the most minimal sketch to isolate the problem based an example temperature read from DS2482_OneWire library examples folder with the PCF8575 added in to read write in a loop together.
I have a jumper connection so I can easily remove the DS2482 SCL and SDA from the bus.
Every time these are connected many of the bits in the read data for IO are pulled low.
Any ideas?
Thanks
Manufacturer page of DS2482: https://www.maximintegrated.com/en/products/interface/controllers-expanders/DS2482-100.html
It seems as if they share the same I2C address, but it could also be a bad I2C bus, or a damaged chip.
Is everything powered with 3.3V ?
Can you run a I2C Scanner for some time ? Is that stable ? Can you see the three I2C addresses ?
What can you tell about your modules and wires ? Can you show a photo ? Do you use pullup resistors ? Do you use modules with pullup resistors ? How long are the wires ? Do you put SDA next to SCL in a flat ribbon cable ?
Yes it looks as though the DS2482 is responding to the reads of the other devices. Writing to the PCF8575 works as expected. The DS2482-800:https://www.maximintegrated.com/en/products/interface/controllers-expanders/DS2482-800.html
is set up identical to the application circuit shown on the page.
Everything is 3.3V. The behaviour is the same at 10kHz as at 100kHz.
Is BusPirate an example of an I2C Scanner?
4k7 pullups are close to the ESP32, wires are short as can see in the photo, can show the scope waveforms but they're very clean as you would expect.
You can find a I2C Scanner sketch in the menu of the Arduino IDE.
There is one here and here.
Never put SDA next to SCL in a flat ribbon cable !
Your scope might not see the glitches that a I2C device might see.
You don't even have to run a I2C Scanner as long as SDA is next to SCL in a flat ribbon cable.
I'm not sure, but I think these are the I2C addresses:
DS2482-800: 0x18 to 0x1F
PCF8575: 0x20 to 0x27
DS3231: 0x68
Thanks for your input.
I've run the scanner from RNT and it returns the device addresses at 0x18,0x20,0x68.
The fundamentals are right because all the peripherals are working together except for DS2482 attached causing read errors for both RTC and IO. The RTC time readings are also corrupted but only when the DS2482 is connected (same as for the IO).
I have torn the ribbon cable so it is now just separate wires.
This is the schematic of the PCF8575 module:
The levels shifters weakens the signal, and the voltage regulator makes the 3.3V lower.
What is the voltage after the voltage regulator ? (VDD).
It is possible to shortcut the voltage regulator with a solder pad or power it with 5V (don't do both).
Your photo shows "472", so there are already two 4k7 pullup resistors. How many more pullup resistors are there ?
Could you check the GND wiring once more ?
Did you know that you can measure the sink current of SDA and SCL in the circuit ? I wrote that here.
The DS2482 needs a decoupling capacitor of 100nF to GND and 3.3V.
You could slow down the slew-rate by the ESP32 by adding a resistor of 100 Ω in the signal path of SDA and SCL.
Can you show your sketch ? If the I2C Scanner works, then it might be a bug in the sketch.
It could be a bad DS2482 after all. Do you have another DS2482 ?
Thanks so much for all the hints and tips and also the schematic!
The info that came with the product listing was very vague. It mentions a regulator but no mention of level shifters which could be significant.
I had connected Vdd to 3.3V and had left Vcc open and the solder bridge across the regulator open. This created a situation where SDA and SCL were coupled by 2x4k7 resistors. (I have the regulator bridged now, still no good)
The ground is a short wire to the ESP32 and I have connected 1uF monolithic ceramic close to the power pins of the DS2482.
There is 4k7 pullups at the ESP32 end so I guess this makes 3x4k7 in parallel on the I2C bus pullup lines (Ok, I would think).
I have placed 82pF caps to ground on SDA and SCL close to the DS2482 to suppress a small undershoot I could see on the scope.
I have disconnected the RTC and reduced the software to simply read the IO without even initialising the DS2482 and this still exposes the problem: most bits read are pulled low whenever the DS2482 is connected to the bus.
Next I will change the IC for a fresh one, paying special attention to grounding everything and soldering the power pins first.
With the minimised setup it is difficult to see how the IC can be o.k, we'll see!
Thanks again.
Can you show a sketch and does the DS3231 module have a battery ?
The DS3231 module is disconnected. The problem is evident with the PCF8575 alongside the DS2482.
#include <OneWire.h> //Arduino\libraries\DS2482_OneWire-master\OneWire.h
#include <DallasTemperature.h>
#include <PCF8575.h>
// This is required for the Arduino IDE + DS2482
#include <Wire.h>
#define INIT_DS2482 1
// When instantiated with no parameters, uses I2C address 18
#if (INIT_DS2482)
OneWire oneWire;
//OneWire oneWire(2); // Use address 20
DallasTemperature sensors(&oneWire);
#endif
TwoWire I2C(0);
PCF8575 IO16(0x20, &I2C);
void printAddress(DeviceAddress deviceAddress)
{
Serial.print("{ ");
for (uint8_t i = 0; i < 8; i++)
{
// zero pad the address if necessary
Serial.print("0x");
if (deviceAddress[i] < 16) Serial.print("0");
Serial.print(deviceAddress[i], HEX);
if (i<7) Serial.print(", ");
}
Serial.print(" }");
}
void setup()
{
Serial.begin(115200);
I2C.begin();
Serial.println(I2C.getClock());
I2C.setClock(12000);
Serial.println(I2C.getClock());
IO16.begin();
IO16.write16(0xffff);
#if (INIT_DS2482)
sensors.begin();
DeviceAddress currAddress;
uint8_t numberOfDevices = sensors.getDeviceCount();
for (int i=0; i<numberOfDevices; i++)
{
sensors.getAddress(currAddress, i);
printAddress(currAddress);
Serial.println();
}
#endif
}
void loop()
{
#if (INIT_DS2482)
Serial.println("Requesting temperatures...");
sensors.requestTemperatures();
DeviceAddress currAddress;
uint8_t numberOfDevices = sensors.getDeviceCount();
for (int i=0; i<numberOfDevices; i++)
{
sensors.getAddress(currAddress, i);
printAddress(currAddress);
Serial.print(": ");
Serial.print(sensors.getTempCByIndex(i));
Serial.println();
}
#endif
for (int i = 0; i < 10; i++) {
uint16_t x = IO16.read16();
Serial.printf("%04X\n", x);
delay(400);
}
Serial.println(I2C.getErrorText(I2C.lastError()));
}
here is the terminal output:
load:0x40078000,len:10944
load:0x40080400,len:6388
entry 0x400806b4
100000
12001
{ 0x28, 0xE8, 0x4B, 0x07, 0xD6, 0x01, 0x3C, 0x98 }
{ 0x28, 0x4F, 0x0F, 0x07, 0xD6, 0x01, 0x3C, 0xB7 }
Requesting temperatures...
{ 0x28, 0xE8, 0x4B, 0x07, 0xD6, 0x01, 0x3C, 0x98 }: 17.75
{ 0x28, 0x4F, 0x0F, 0x07, 0xD6, 0x01, 0x3C, 0xB7 }: 17.56
4141
4141
4141
4141
4141
4141
4141
4141
4141
4141
OK
Requesting temperatures...
{ 0x28, 0xE8, 0x4B, 0x07, 0xD6, 0x01, 0x3C, 0x98 }: 17.75
{ 0x28, 0x4F, 0x0F, 0x07, 0xD6, 0x01, 0x3C, 0xB7 }: 17.56
4141
4141
4141
4141
4141
4141
4141
4141
4141
4141
OK
Requesting temperatures...
{ 0x28, 0xE8, 0x4B, 0x07, 0xD6, 0x01, 0x3C, 0x98 }: 17.69
{ 0x28, 0x4F, 0x0F, 0x07, 0xD6, 0x01, 0x3C, 0xB7 }: 17.62
4141
4141
4141
4141
now with the DS2482 i2c lines disconnected:
Requesting temperatures...
FFFF
FFFF
FFFF
FFFF
FFFF
FFFF
FFFF
FFFF
FFFF
FFFF
OK
Requesting temperatures...
FFFF
FFFF
FFFF
FFFF
FFFF
FFFF
FFFF
FFFE
FFFE
FFFE
OK
Requesting temperatures...
At the very end LSB is pulled low by a pushbutton (PCF8575 working as expected).
I now have 150R in series with the I2C pins of the ESP32 (after 4k7 pullups). The CRO measurements are taken from downstream of this close to the DS2482.
Below is reading 0xFFFF from the PCF8575 (DS2482 disconnected):
Below is reading 0x4141 from the PCF8575 (DS2482 connected):
The ESP32 (and also the ESP8266) have been upgraded a lot over the last years. They are now much more compatible with normal Arduino code.
Why would you add a I2C object alongside the object of the Arduino-compatible Wire library ? Use the 'Wire' object also for the PCF8575 library.
Use the most simple, most common things. Follow the KISS rule.
Don't set the SCL clock to 12kHz, that is very low. Don't set it at all, use the default.
#include <Wire.h>
void setup()
{
// Use no parameters for the default pins.
// Or use Wire.begin( sda pin, scl pin);
Wire.begin();
...
}
Please show the new sketch.
Can you tell which PCF8575 library you use ? I would like to check that code.
Is it the RobTillaart version ? https://github.com/RobTillaart/PCF8575. He makes good libraries, so I assume the library is okay.
If a I2C Scanner can run for a while without problem, then the I2C should work most of the time. So the next step was your sketch. This started as a very weird problem, but after all it is just a normal problem. Stay updated and follow the KISS rule.
The Wire.h is the built in I2C one you mention. Declaring the object explicitly means you can call it to say specify the clock frequency.
The PCF8575.h is the RobTillaart one.
The scanner works with my project perfectly.
The DS2482 works with an attached network of temperature sensors exactly as expected.
The PCF8575 works exactly as expected except when a DS2482 is attached to the I2C bus (regardless of whether (or not) the sw initialises or in anyway addresses the device).
Show a sketch that uses the normal Wire library please.
To set the clock, the function Wire.setClock( 100000);
can be used.
Thanks for all the information and the scope picture. That is so weird, that I almost want to ignore it The idea that someone pulls it low just does not fit into my brain
If it is not the sketch, then the DS2482 could be broken.
I did actually swap out the DS2482 with identical results.
At this point I cannot accept that it is sw bug because I can see that the software is doing what it is supposed to i.e a 16bit read from a PCF8575. I can see the 16bit read operation with my own eyes on the scope. That operation get corrupted whenever the DS2482 is physically connected to the bus.
Talk about KISS
Anyhow I do intend to get to the bottom of this eventually and I will most definitely post back to this thread when I do! Thanks for your help so far.
In the meantime I really want to be developing the software of my project, so to that end I've customised a DS2482_OneWire library to use a bit banged TwoWire instance using spare GPIO pins so that it communicates over a dedicated I2C bus.
A word about I2C. Its a synchronous transport which means it should function over a wide range of clock rates (even varying rates) and this can be a great way of eliminating signal integrity issues as data is sampled at rising edge of the clock IIRC. In this way line ringing and slow rise/fall times can be overcome with a slower clock rate (to a point, and not without exceptions). This has been my experience for what it's worth.
A few thoughts:
- If there was a award for the weirdest problem of the year, you would probably win it
- Falling back to the most simple, most standard, and most normal way is how to solve a problem. You are the only one who this combination of things. So after using the Wire library with the "Wire" object at 100kHz, then you could try other libraries. Their could be a bug somewhere. Make a simple sketch to prove to me that it does not matter
and show me the sketch.
- I can not find someone else with the DS2482 and the same problem. Perhaps the DS2482 itself has no issues.
There was a chip (I forgot which one) that caused trouble on the I2C bus, so the manufacturer changed the datasheet and wrote that their chip must be the only one on the I2C bus ! These things really happen - Just accept that it does not work is not a bad way to solve a problem. I think you did the right thing by giving the DS2482 its own I2C bus.
- With resistors in the I2C path towards the DS2482 and a analog scope, you could see how exactly the DS2482 attacks the I2C bus.
- According to the datasheet, I think that the DS2482 and PCF8575 start at 0Hz. However, a clock speed of 12kHz is very low. That is really weird.
- I have to disagree with you. There is no wide clock range, and a lower clock speed can only solve a capacitance problem of wires. The crosstalk between SDA and SCL can not be solved with that. See my: How to make a reliable I2C bus and pay attention to the famous "page 60".
[ADDED]
Some Wire libraries have glitches, that should normally be no problem if a sensor is according to the I2C standard. Even the Wire library for the Arduino Uno has a hardware glitch, which some software I2C libraries do not have (I have deliberately made this not similar to the Wire library, because I didn't want that glitch).
The DS2482-800 datasheet about the I2C bus: Needs delay after power on before using the I2C bus; Needs extra delays around the START and STOP and Repeated START conditions; If it sees signals that are fast (400kHz) then the signals may not be too slow or something like that (datasheet, note 12, page 4).
The DS2482-800 has indeed a non-standard I2C interface.
Sorry for the long post. I think we can see the bottom that you were going to
Thanks indeed for the advice, info and links!
Very useful stuff.
I think we can both agree that "weird" problems don't go away. I suppose one can try to ignore them with a workaround (which I have kind of done). But if there is some misuse of basic I2C i/o I am doing then surely I will hit this again. And when I do I will be back here to report my stuff up or extraordinary discovery!
Nice thing about this ESP32 platform is IO pins can be mapped so that I should be able to apply the second I2C hw port for the DS2482.
All the I2C comms is working well now but I assumed that if you assign arbitrary pins to scl,sda with Wire library then the implementation is bit banged.
I will try this approach: Tutorial here. I'll give it a try.
I will try once more for the last time, Koepel's law: https://forum.arduino.cc/t/whats-wrong-with-bme280/349380/4?u=koepel
Did you look at the code I posted and consider the case where
#define INIT_DS2482 0
It doesn't get any simpler than that.
This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.