Low speed onewire variation

All ESP32 boards running MicroPython.
Target audience: MicroPython users with an ESP32 board.
Post Reply
tll
Posts: 13
Joined: Fri Feb 07, 2020 10:16 am

Low speed onewire variation

Post by tll » Tue Mar 03, 2020 6:15 pm

I am evaluating the ESP32 for a home project I have in mind. I have a sprinkler controller that has a remote receiver connected via a custom one way onewire protocol running at 480 Hz. There is no device address involved, and messages consist of 7 bytes inbound. What I know about it, I have learned from somewhere else posts about an arduino based hack. I have not hooked a logic analyzer myself.

I would like to intercept the onewire, read it into the ESP32 to capture the request and then echo it to the controller. At the same time, have an HTTP application by which an iPhone can issue commands which will result in feeding a 7-byte command string to the controller. I want to keep the remote functional so the service people can use it for winterizing, etc... while we use the iPhone with a more versatile interface, like ad hoc programs and such.

I have been looking at the _onewire support and the timings appear to be hard coded in C, and also, I am not sure how the lack of addressing and the one-way factor will play in. I am not sure how complex is the process of recompiling _onewire, which I am afraid would require rebuilding the firmware. I assume I would have to setup a tool chain on Windows to do it.

At 480Hz, the 1-bit will be a 1.875ms low pulse and a 0-bit 208us low pulse. Instead of having to modify the existing _onewire, I was thinking of using dual edge interrupts on GPIO and a microsecond timer and write it from scratch. I have read some past posts about the unpredictability of interrupt handling timings. Was that fixed to provide consistency or is it still a problem?

I swill appreciate any comments and suggestions.

PS: My fallback plan would be something like an FT232H break board from Adafruit connected to a RaspberryPi Zero W. (I am afraid that debugging the FT232H commands will not be fun)

tll
Posts: 13
Joined: Fri Feb 07, 2020 10:16 am

Re: Low speed onewire variation

Post by tll » Tue Mar 03, 2020 11:28 pm

Thinking aloud about timer interrupts to implement the write... is it possible/acceptable to toggle a GPIO and rearm a ONE-SHOT timer or change the frequency of a PERIODIC one from inside the timer IRQ call back routine?

User avatar
jimmo
Posts: 2754
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: Low speed onewire variation

Post by jimmo » Wed Mar 04, 2020 3:30 am

This is going to be tricky to do to the required precision in Python -- this is why the _onewire module exists.

Compiling the firmware for ESP32 isn't that tricky. If you're one Windows, you might want to take a look at WSL.

There are some pending updates to the build documentation here which might help you -- https://github.com/micropython/micropython/pull/5713

One thing to note is that the ESP32 has some dedicated hardware for generating and receiving specific waveforms (the RMT peripheral). MicroPython does have some support for generating, but not sure if it will be possible to use for this as I imagine you need an open collector output. (I don't know much about RMT though).

tll
Posts: 13
Joined: Fri Feb 07, 2020 10:16 am

Re: Low speed onewire variation

Post by tll » Wed Mar 04, 2020 6:07 am

jimmo wrote:
Wed Mar 04, 2020 3:30 am
This is going to be tricky to do to the required precision in Python -- this is why the _onewire module exists.

Compiling the firmware for ESP32 isn't that tricky. If you're one Windows, you might want to take a look at WSL.

There are some pending updates to the build documentation here which might help you -- https://github.com/micropython/micropython/pull/5713

One thing to note is that the ESP32 has some dedicated hardware for generating and receiving specific waveforms (the RMT peripheral). MicroPython does have some support for generating, but not sure if it will be possible to use for this as I imagine you need an open collector output. (I don't know much about RMT though).
Thank you for the answer. I have to look at the _onewire and see what it does. I wonder about the implications of hard coded delays of almost 2ms to write a bit.

On the other hand, the RMT peripheral, although quite green, seems may do the trick to write the 7 byte sequence. The idle level is not yet configurable, but I suspect I would need a level conversion to deal with 5V, so may or may not be an issue. I have to think about it.

User avatar
romeotango
Posts: 29
Joined: Tue Jun 16, 2015 10:52 am
Location: Germany

Re: Low speed onewire variation

Post by romeotango » Mon Mar 09, 2020 7:11 am

Although it is certainly very interesting and didactically valuable, it obviously makes a lot of effort to operate onewire safely and reliably.
https://www.artekit.eu/products/breakou ... 2482s-100/
This is a breakout that makes many things easier, even the high power supply is implemented.
Yes, this is not the pure doctrine of micropython, but it prevents many errors, whose search costs time and manpower.
RT

User avatar
tve
Posts: 216
Joined: Wed Jan 01, 2020 10:12 pm
Location: Santa Barbara, CA
Contact:

Re: Low speed onewire variation

Post by tve » Mon Mar 09, 2020 4:00 pm

romeotango wrote:
Mon Mar 09, 2020 7:11 am
Although it is certainly very interesting and didactically valuable, it obviously makes a lot of effort to operate onewire safely and reliably.
https://www.artekit.eu/products/breakou ... 2482s-100/
This is a breakout that makes many things easier, even the high power supply is implemented.
Yes, this is not the pure doctrine of micropython, but it prevents many errors, whose search costs time and manpower.
RT
While I can highly recommend the chip used in that breakout for 1-wire networks that extend beyond 1-2 devices, it won't help the OP who is trying to interface to a non 1-wire device using a protocol that sounds similar to 1-wire but isn't 1-wire.

tll
Posts: 13
Joined: Fri Feb 07, 2020 10:16 am

Re: Low speed onewire variation

Post by tll » Mon Mar 09, 2020 8:53 pm

tve wrote:
Mon Mar 09, 2020 4:00 pm
romeotango wrote:
Mon Mar 09, 2020 7:11 am
Although it is certainly very interesting and didactically valuable, it obviously makes a lot of effort to operate onewire safely and reliably.
https://www.artekit.eu/products/breakou ... 2482s-100/
This is a breakout that makes many things easier, even the high power supply is implemented.
Yes, this is not the pure doctrine of micropython, but it prevents many errors, whose search costs time and manpower.
RT
While I can highly recommend the chip used in that breakout for 1-wire networks that extend beyond 1-2 devices, it won't help the OP who is trying to interface to a non 1-wire device using a protocol that sounds similar to 1-wire but isn't 1-wire.
I agree, that chip would not help me. On the other hand, I have given a try to transmitting a sequence with ESP32/RMT and it is trivial... It worked at the first try. I did not even get a syntax error! I had to hook it to el cheapo logic analyzer to believe it.

Now I need to solve the receiving side and figure out what the command bit sequences are supposed to be. Thinking on how to set up an RPi + SIGROK + LA with the controller in the garage, so I can capture and analyze sequences from the warmth of my office. The garage is still below freezing.

tll
Posts: 13
Joined: Fri Feb 07, 2020 10:16 am

Re: Low speed onewire variation

Post by tll » Thu Apr 02, 2020 2:22 pm

I have been making some progress on this. Implementing transmission of the pulse train using the existing RMT support was easy. It has taken longer to work on the receiving side. What I have done for testing is to feed back the transmitted pulse train to the receiving pin and tie that pin to an interrupt that collects pulse edge microseconds on a linear buffer. The main loops, starts the listener, transmits, sleeps a little and processes the input buffer, keeping track of pulse timing min/max statistics. With no other load, it is able to keep track, not loosing a pulse. I am using viper for the interrupt and able to handle 208uS pulses pretty consistently:

Code: Select all

    @micropython.viper
    def pulse_isr(self, pin):
        ticks = int(time.ticks_us())
        idxs = ptr32(self.index)
        ix = idxs[0]                        # put index

        if self.pin():                      # raising edge
            rise = ptr32(self.rise_ticks)
            rise[ix]=int(ticks)
            idxs[0] = int(ix+1) 
            
        else:                                # dropping edge
            drop = ptr32(self.drop_ticks)
            drop[ix] = int(ticks)


While testing, I have run into a problem. I am running it under REPL, invoking main() manually, and to stop it I use CTRL-C and then run it at will. Today, in a new run after CTRL-C, I got this persistent error:

Code: Select all

>>> test_hunter_waves.main()
E (59840) rmt: rmt_driver_install(728): RMT driver already installed for channel
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "test_hunter_waves.py", line 22, in main
  File "hunter.py", line 172, in __init__
The question is if there is a way to handle this error. May be to trap it and force a full reset?

EDIT: Never mind, I'll use CTRL-D

tll
Posts: 13
Joined: Fri Feb 07, 2020 10:16 am

Re: Low speed onewire variation

Post by tll » Fri Apr 10, 2020 3:47 pm

An update on the saga of detecting the pulses... I tried a few approaches

1. RISE | DROP edge interrupt on the pin and capturing ticks on linear buffer for drop and rise. It seemed to work at the beguining when I had an simple delay loop on the main. Interestingly, when I modified the code for asyncio, it started to have excessive latency problems.

2. I tied the input signal to two pins, and set two different ISRs for each edge. The ISRs where a bit lighter because did not have to read the pin status, and also they were not re triggered. It helped some, but there were still some random occurrences of very high latency.

3. I went back to a single pin, with IRQ on drop edge, and using machine.time_pulse_us with a timeout of 300us, to discriminate the 200us pulses. Having the ISR executing that long may have side effects, but thought it was worth a try. The result was that most 200us pulses were timed somewhere around 100us, which was great, but there were occasional latency caused problems.

With the results from #3, I thought that if I could insert an external monostable pulse stretcher in the input line, to bring the 200us to something like 300us, it may work consistently. So I went to my favorite electronics forum, down under, and asked a question about the stretcher circuit. After a few iterations, where as always, I was required to fully describe my problem. When I said that pulse waves were based on 10 units of 200us, with 1/9 and 9/1 shapes to encode 0/1, someone jumped in suggesting that if it was read with a UART as start-8bit-stop asynch, it should capture X00 and XFF bytes. I have tried it and it works!

tl;dr From an EE forum got the suggestion to handle the signal with a UART as START-8BIT-STOP. It works! It captures X00 and XFF bytes for short and long pulses respectively. Now to look for the next challenge!

PS: On the last stages of the testing, I flashed the daily in because I heard it had new asyncio support. FWIW, let me say that my feeling is the latest firmware seems to have shorter interrupt process latency.

Post Reply