Welcome to the Pycom forum Forum
    • \[\[global:header.categories\]\]
    • \[\[global:header.recent\]\]
    • \[\[global:header.tags\]\]
    • \[\[global:header.popular\]\]
    • Login

    Explore Pybytes | Official Documentation | Report a Firmware Bug/Issue | GitHub

    [solved] Onewire DS18X20 reading not stable with LoPy4 (no problem with LoPy)

    Scheduled Pinned Locked Moved Issues & Bugs
    lopy4onewire
    23 Posts 3 Posters 8.0k Views 3 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • affoltepA Offline
      affoltep
      last edited by affoltep

      The following example code from the doc, with the newest onwire.lib and firmware v1.14.0.b2 does not run stable on LoPy4.

      from machine import Pin
      from onewire import DS18X20
      from onewire import OneWire
      
      #DS18B20 data line connected to pin P10
      ow = OneWire(Pin('P10'))
      temp = DS18X20(ow)
      
      while True:
          print(temp.read_temp_async())
          time.sleep(1)
          temp.start_convertion()
          time.sleep(1)
      

      Often you will get a "None" as response or sometimes the correct values, but with runaway values to 0.0.
      I tried to bring more reliablilty with external pull-up, but it does not help.
      Tested on two independent LoPy4, same behaviour. LoPy is reading DS18X20 sensors stable.

      robert-hhR 2 Replies Last reply Reply Quote 0
      • robert-hhR Offline
        robert-hh @affoltep
        last edited by

        @affoltep If all other parameters are the same, like firmware version, that could be caused by the differences in the RAM timing of the two devices. LOPY4 uses psRAM for the heap, which is subject to cache misses. A cache miss causes delay in program execution of about 300 µs.
        Besides that, code on a ESP32 cannot be expected to have a reliable timing in the range <= 1 ms, unless you make it "sticky". That''s only possible for C code.

        L 1 Reply Last reply Reply Quote 1
        • L Offline
          livius @robert-hh
          last edited by livius

          @robert-hh
          interesting assumption.

          @affoltep
          are you sure that all is same?
          What is your value for external pullup? I always use for DS18X20 external pullup 4.7K.
          And reading is ok also for long cable like 10 meters. But i do not have Lopy4 to test behavior, and can not help more without.

          think about people first, then computers

          robert-hhR 1 Reply Last reply Reply Quote 0
          • robert-hhR Offline
            robert-hh @livius
            last edited by

            @livius @livius You could use any newer device too, like a GPy, FiPy, WiPy3 or ESP32 with a WROVER module.

            1 Reply Last reply Reply Quote 0
            • affoltepA Offline
              affoltep
              last edited by

              @livius , @robert-hh : Thx guys. Think we are on a promising track.

              I have done some additional investigations. I flashed back to firmware 1.9.2.b2. (the newest firmware 1.15.0.b1 generates a problem running LoPy with deepsleep shield with ,and only with battery power --> always wakes up due pin interrupt. Apparently newest firmware generates a problem if there are not 5V present.

              So both LoPy4 and LoPy are running with 1.9.2.b2 identical code. I use a 10kOhm pull-up on the LoPy4 and no resistor on LoPy (just internal pull-up by the onewire config). As I discovered the instability of reading values on LoPy4 I add the resistor. Unfortunately I didn't had a 4.7k, so I took a 10k, but it shouldn't be an issue.

              So at the moment, the assumption from @robert-hh seems to be the most possible. Does one of you work for pycom? It would be nice if you could integrate a C lib for onewire communication in the firmware.

              One of the LoPy4 I tested is slightly more stable than the other, but never on the bullet proof level of the LoPy

              robert-hhR 1 Reply Last reply Reply Quote 0
              • robert-hhR Offline
                robert-hh @affoltep
                last edited by robert-hh

                @affoltep @livius I made little test, letting this simple script run on both a fipy and a lopy.

                from machine import Pin, enable_irq, disable_irq
                from utime import sleep_us
                
                pin = Pin("P11", Pin.OUT)
                
                while True:
                    state = disable_irq()
                    pin(1)
                    sleep_us(20)
                    pin(0)
                    enable_irq(state)
                    for _ in range (100):
                        b = bytearray(200)
                        b[0] = _
                

                So it outputs a 20 µs pulse and then consumes some memory. I logged the output with the oscilloscope in pertinence mode, so you see the varying pulses (fipy yellow, Lopy green):
                FiPy:
                0_1517663344547_fipy_pintoggle.jpg
                LoPy:
                0_1517663368715_lopy_pintoggle.jpg
                Both results are not good, like there is no pulse shorter than ~40 µs, but the result on FiPy is worse, extending the pulse sometimes to over 500 µs.
                Adding a gc.collect() immediately before the pulse creating sequence improve the situation drastically. The longest pulse seen then for FiPy is 65 µs, and Lopy shows always about 30 µſ. Please note that the time scale has changed in the pictures below.
                0_1517664332558_fipy_pintoggle_gc.jpg
                0_1517664727129_lopy_pintoggle_gc.jpg

                L 1 Reply Last reply Reply Quote 0
                • L Offline
                  livius @robert-hh
                  last edited by robert-hh

                  @robert-hh
                  This result is on clear boards or on some extension board? And same sensor module?
                  Because it looks strange.

                  think about people first, then computers

                  robert-hhR 1 Reply Last reply Reply Quote 0
                  • robert-hhR Offline
                    robert-hh @livius
                    last edited by

                    @livius This is on a plain board, nothing else started after boot expect for connecting the WiFi to an AP.
                    The FiPy was sitting on an expansion board, the LoPy on a breadboard, Firmware 1.14.0.b1. No sensor module attached, just the output on P11.
                    Besides that, from similar test, like IRQ latency, the results are NOT surprising. Making timing precise on chips with serial flash (and serial RAM) requires a lot of consideration.

                    1 Reply Last reply Reply Quote 0
                    • affoltepA Offline
                      affoltep
                      last edited by

                      @robert-hh, @livius I included a gc.collect() in the reset, read_bit and write_bit functions of the onewire lib.
                      Of course it takes now ages to get a temperature value (~15s) but it seems a little bit more reliable. There are still missreadings, but it seems indeed a little bit better. Will do some tests over night to proof...

                      Any other ideas to get a workaround? Would it be possible to solve this issue by firmware?

                      robert-hhR 2 Replies Last reply Reply Quote 0
                      • robert-hhR Offline
                        robert-hh @affoltep
                        last edited by

                        @affoltep It should be sufficient to put it at the start of read_bytes() and write_bytes().

                        1 Reply Last reply Reply Quote 0
                        • robert-hhR Offline
                          robert-hh @affoltep
                          last edited by robert-hh

                          @affoltep Looking at the example code for readbit(), both sleep_us(1) are obsolete, since the shortest effective distance I have seen between a pin(x) and pin(y) is 3 µs, and the call of sleep_us() alone takes at least 3-4 µs.

                              def read_bit(self):
                                  sleep_us = time.sleep_us
                                  enable_irq = machine.enable_irq
                                  pin = self.pin
                          
                                  pin(1) # half of the devices don't match CRC without this line
                                  i = machine.disable_irq()
                                  pin(0)
                                  sleep_us(1) # should be deleted
                                  pin(1)
                                  sleep_us(1) # should be deleted
                                  value = pin()
                                  enable_irq(i)
                                  sleep_us(40)
                                  return value
                          

                          write_bit() is less critical, although the sleep_us(1) may also not be needed.

                          1 Reply Last reply Reply Quote 1
                          • robert-hhR Offline
                            robert-hh @affoltep
                            last edited by

                            @affoltep I made another test, rebuilding just the initial part of write_bit(1) (which is similar to read_bit()). It shows the Initial low period with and w/o the sleep_us(1) lines.
                            Timing with sleep_us(1)
                            0_1517689664338_pulse_w_sleep.jpg
                            Timing without sleep_us(1)
                            0_1517689521083_pulse_wo_sleep.jpg
                            With the sleep_us(1) call, this initial period can extend to about 30 µs, effectively writing a 0 or missing the read window at 15µs. Without that sleep, the initial pulse time is still sometimes extend, but much more seldom and shorter than 10µs, being still in the safe range.

                            affoltepA 2 Replies Last reply Reply Quote 2
                            • affoltepA Offline
                              affoltep @robert-hh
                              last edited by

                              @robert-hh Wow, this could mess up the whole communication at the beginning. I have done now all modifications, including the gc.collect() command in the beginning of read_bytes and write_bytes.
                              I will let the device run during night to check, whether the communication is more stable. Will let you know more tomorrow.

                              BTW. Your support is incredible! Many thanks

                              1 Reply Last reply Reply Quote 0
                              • affoltepA Offline
                                affoltep @robert-hh
                                last edited by

                                @robert-hh @livius It works! Removing the sleep_us(1) in the code did the trick. Measurements are now stable like with LoPy.
                                I will place a pull request for the onewire lib.

                                Thanks again for all the help, you made my day

                                L 1 Reply Last reply Reply Quote 0
                                • L Offline
                                  livius @affoltep
                                  last edited by livius

                                  @affoltep
                                  not be too fast.
                                  This is braking change for e.g. Wipy2.
                                  The second wait is critical here and must stay.

                                  Then i suppose parameter like addWait is required here
                                  default=True and for LoPy4 set to False.

                                  think about people first, then computers

                                  affoltepA robert-hhR 3 Replies Last reply Reply Quote 0
                                  • affoltepA Offline
                                    affoltep @livius
                                    last edited by

                                    @livius Hm, but LoPy, which is from architecture view similar to Wipy2 can as well not generate a 1us break. Is it really needed?
                                    I tested the new lib as well on Lopy and it did work without the seleep_us(1)

                                    1 Reply Last reply Reply Quote 0
                                    • robert-hhR Offline
                                      robert-hh @livius
                                      last edited by robert-hh

                                      @livius I agree about the second sleep, but even on WiPy2 it should work without the first sleep. Did you try that it fails? The D18B20 requires a minimum low time of 1µs. On my LoPy, the pin(0)/pin(1) sequence creates a low pulse of ~2 µs. Changing that to:

                                              addWait = False
                                              pin(0)
                                              if addWait:
                                                  sleep_us(1)
                                              pin(1)
                                      

                                      changes the pulse to ~3µs on the LoPy, sometimes extended to 4 µs.
                                      On the FiPy with that change the basic pulse width is too 3 µs, but pulses are more frequently extended and up to more than 15 µs, breaking the communication with the DS18B20.
                                      And @affoltep could try the variant w/o sleep with his LoPy too. I have no DS18B20 here, otherwise I would have tried that already.

                                      L 1 Reply Last reply Reply Quote 0
                                      • robert-hhR Offline
                                        robert-hh @livius
                                        last edited by robert-hh

                                        @livius @affoltep Just tried the same code on the LOLIN32 pro, which should be similar to a WiPy3. That devices behaves the same way as the FiPy (not surprising).
                                        Next attempt on a Wemos LOLIN32 lite, which is closest to the WiPy2 I can get, which shows the same figures as the LoPy.
                                        All tested with the "if addWait" addition.
                                        (sorry @daniel and @jmarcelino, that I do not have the full set of Pycom modules here)

                                        affoltepA 1 Reply Last reply Reply Quote 0
                                        • affoltepA Offline
                                          affoltep @robert-hh
                                          last edited by

                                          @robert-hh @livius Ok, just do a short summary:

                                          • I removed the 4 sleep_us(1) from the actual onewire.py lib (2 from read_bit() and 2 from write_bit()
                                          • Tested both LoPy4 and LoPy with the new onewire.py lib
                                          • LoPy runs similar stable as with the "old" onewire.py lib (including sleep_us(1))
                                          • LoPy4 runs much more stable with the new onewire.py lib, no missreadings anymore

                                          From my point of view no sleep_us(1) is needed for Lopy.

                                          I just have done tests with a DS18X20 (no other onewire devices)

                                          robert-hhR 1 Reply Last reply Reply Quote 0
                                          • robert-hhR Offline
                                            robert-hh @affoltep
                                            last edited by robert-hh

                                            @affoltep Looking at the data sheet, that seems OK. Faster is better. For reading, it says:
                                            "Output data from
                                            the DS18B20 is valid for 15μs after the falling edge that
                                            initiated the read time slot. Therefore, the master must
                                            release the bus and then sample the bus state within
                                            15μs from the start of the slot."

                                            1 Reply Last reply Reply Quote 0

                                            Hello! It looks like you're interested in this conversation, but you don't have an account yet.

                                            Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

                                            With your input, this post could be even better 💗

                                            Register Login
                                            • 1
                                            • 2
                                            • 1 / 2
                                            • First post
                                              Last post

                                            Pycom on Twitter

                                            Pycom