8000 OneWire timing issue · Issue #4116 · micropython/micropython · GitHub
[go: up one dir, main page]

Skip to content

OneWire timing issue #4116

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
rnovacek opened this issue Sep 10, 2018 · 6 comments
Closed

OneWire timing issue #4116

rnovacek opened this issue Sep 10, 2018 · 6 comments

Comments

@rnovacek
Copy link

I'm trying to use MicroPython on Wemos D1 mini (esp8266) to read temperature from DS18b20 sensor.

Reading values from this sensor is very unreliable for me. I get the temperature like once in 20 attempts to read the temperature. Other reads thrown an OneWireError exception during OneWire.reset(True) method or no device was found. This is the code I used (from the MicroPython docs):

import time
import machine
import onewire, ds18x20

# the device is on GPIO12
dat = machine.Pin(12)

# create the onewire object
ds = ds18x20.DS18X20(onewire.OneWire(dat))

# scan for devices on the bus
roms = ds.scan()
print('found devices:', roms)

# loop 10 times and print all temperatures
for i in range(10):
    print('temperatures:', end=' ')
    ds.convert_temp()
    time.sleep_ms(750)
    for rom in roms:
        print(ds.read_temp(rom), end=' ')
    print()

I tried flashing Arduino to the same board with same sensor and it worked flawlessly.

I compared source codes for both 1-wire libraries and discovered one difference:
The second sleep in the reset function is 40us for MicroPython, but 70us for Arduino.

Sources:
Arduino: https://github.com/PaulStoffregen/OneWire/blob/master/OneWire.cpp#L187
MicroPython: https://github.com/micropython/micropython/blob/master/extmod/modonewire.c#L37

So I tried following monkeypatch to use the timings from Arduino:

import onewire
def reset(self, required=False):
    self.pin.value(0)
    time.sleep_us(480)
    self.pin.value(1)
    time.sleep_us(70)
    status = self.pin.value()
    time.sleep_us(420)
    return status

onewire.OneWire.reset = reset

With this, I get the correct readings every time. There's also different number for the 3rd sleep, but that doesn't seem to matter.

I found that master should wait 15-60us after reset before reading slave presence signal:
https://datasheets.maximintegrated.com/en/ds/DS18B20-PAR.pdf (page 13) and then it has 60-240us to read the presence (I hope I interpreted the datasheet correctly).

TLDR: I think the second sleep time should be changed from 40us to 70us.

@robert-hh
Copy link
Contributor
robert-hh commented Sep 10, 2018

I used the same combination (Wemos d1 Mini and DS18B20's) with that sample script without any problems. Over days, I have not seen any suspicious value. So I have one question: did you install the 4.7 kOhm resistor between the data line and Vcc of the DS18B20 sensor?

Or maybe you have an defective sensor, or the connecting wire is too long, creating a larger capacitive burden.

Side note: Questions like this are better discussed at the forum: http://forum.micropython.org/

@rnovacek
Copy link
Author

Yeah, I tried with and without the 4.7kOhm resistor, tried powering from both 3.3V and 5V. Maybe I have some wrong DS18b20 (tried two, but from same shop - maybe some clones or whatever).

My point is that MicroPython doesn't adhere to the datasheet (that says 15-60us), I think it means at least 60us to be sure.

Here are a couple more 1-wire implementations:
https://github.com/jabelch/onewire/blob/master/timing.c#L29 - 70us
https://github.com/dsiroky/OneWire/blob/master/onewire.c#L22 - 70us
https://github.com/bigjosh/OneWireNoResistor/blob/ESP8266/OneWire.cpp#L171 - 70us

There seem to be quite big consensus on 70us. Is there any reason why MicroPython uses 40us?

@robert-hh
Copy link
Contributor
robert-hh commented Sep 11, 2018

Looking at my devices here, the slave responds within 30 µs and pulls the line down for 120µs. Since the maximum response time of the slave is 60µs, it is indeed more safe to wait a little bit longer, like 70-80 µs.
Edit: I do not know whether that will be in conflict with other devices.
Edit2: This is the line in questions: https://github.com/micropython/micropython/blob/master/extmod/modonewire.c#L37

@sulimma
Copy link
sulimma commented Sep 28, 2018

There is a bug in in the library.
According to this document, table 2-1 the delay I should be 70us:
https://pdfserv.maximintegrated.com/en/an/AN126.pdf

However in the sourcecode of micropython the delay is set to 40us.
I don't have access to the code right now, but I believe it is in onewire.c,

@sulimma
Copy link
sulimma commented Sep 29, 2018

OK, here are the details:
in file micropython-1.9.4/ports/esp32/esponewire.c
in line 40 the second entry should be 70 not 40.
To conform with the standar, line 40 should read:
uint16_t esp_onewire_timings[9] = {480, 70, 420, 5, 5, 40, 10, 50, 10};
Please fix.

@dpgeorge
Copy link
Member

Thanks for the report about this, and for tracking down the issue. The fix to change the delay from 40us to 70us was done in 4904663

I tested it on a PYBv1.0, esp8266 and esp32, and it works for me with the new timings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants
0