-
-
Notifications
You must be signed in to change notification settings - Fork 8.2k
esp32: repeated RMT pulses when using loop(True)
#6167
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
Comments
I have forked micropython/micropython to jonathanhogg/micropython and committed this change to the With the same above code, I now get the following – correct – output: |
Note that I suspect that #5787 is also caused by this bug |
Otherwise the RMT will repeat pulses when using loop(True). This repeating is due to a bug in the IDF which will be fixed in an upcoming release, but for now the accepted workaround is to swap these calls, which should still work in the fixed version of the IDF. Fixes issue #6167.
Fixed by 3a9d948 |
Hmmm… bad news. It doesn't look like this has properly fixed the problem. The [Props to @mogplus88 for alerting me to this over in mattytrentini#11] |
Small failing example:
First set of three pulses appear on pin 12, the second call starts but there are no further pulses and the interpreter locks up until a hard reset. I swapped the So far, this is all as tested on IDF v4.0.1. [@dpgeorge can you re-open this issue for me?] |
So I've gone back to my previous fix for this problem – turning off the TX interrupt when looping is enabled – and everything operates as I would expect it to: repeated calls to If Using So it looks like:
@mogplus88: I am going to push my changes to https://github.com/jonathanhogg/micropython/tree/rmt_fix if you are able to rebuild MicroPython and try them. Or let me know if you want me to send some pre-built firmware to you. |
OK, with some more digging I have found that calling Whichever way you dice it, the real problem here appears to be with the TX interrupt. The hanging of In terms of getting something approaching sane behaviour for >>> from esp32 import RMT
>>> from machine import Pin
>>>
>>> pin = Pin(12, Pin.OUT)
>>> rmt = RMT(0, pin=pin, clock_div=128)
>>>
>>> rmt.write_pulses([0,0])
>>> rmt.loop(True)
>>> rmt.write_pulses([2500, 7500, 5000, 5000, 7500, 2500])
>>> rmt.wait_done()
False
>>> rmt.loop(False)
>>> rmt.wait_done()
True Calling Really, I think that enabling looping should be accompanied by decrementing the semaphore and then turning off the interrupt. Decrementing the semaphore would force a wait until the current pulse train is complete – if you've just called In the absence of that, it may be that a Handing further consideration over to @dpgeorge and @mattytrentini… |
Had a brainwave while doing the washing-up and realised that the existing API can be retained by simply disconnecting the action of calling
This means that calling >>> from esp32 import RMT
>>> from machine import Pin
>>>
>>> pin = Pin(12, Pin.OUT)
>>> rmt = RMT(0, pin=pin, clock_div=16)
>>>
>>> rmt.wait_done()
True
>>> rmt.loop(True)
>>> rmt.write_pulses([2500, 7500, 5000, 5000, 7500, 2500])
>>> rmt.wait_done()
False
>>> rmt.write_pulses([5000, 5000])
>>> rmt.wait_done()
False
>>> rmt.write_pulses([10000, 10000])
>>> rmt.wait_done()
False
>>> rmt.loop(False)
>>> rmt.wait_done()
True
>>> rmt.write_pulses([10000, 10000])
>>> rmt.write_pulses([5000, 5000])
>>> I've confirmed that all of the above works against esp-idf v3.3.2 as well (and verified actual results with an oscilloscope). Code changes in my rmt_fix branch. |
@jonathanhogg thanks for the offer but I have never tried Micropython. All my testing has been done in C. Maybe I should give it a shot. I've got a Pycom WiPy... ;-) Ian |
@mogplus88 yes, sorry, I realised after making the offer that your messages only referred to the C API! Still, my results above should apply the same to your code and I'd be interested to hear your results. Key things I am doing first time around:
Then for each time I want to update the pulses:
This last soft-shoe-shuffle is to ensure there's no glitches in the output around switching trains. Calling |
@jonathanhogg thanks for spelling it out for me. You may have guessed I am not a techhead! But I'm okay at following instructions. Cheers, PS dunno if it helps, but I have implemented similar functionality with an Atmel processor using PWM. I got it to loop around an array and load the next pulse width from the next member of the array (done in an ISR). It was then possible to update the array at any time as the pwm compare registers are "double buffered", i.e. not updated until the pwm pulse has been generated, then the new value is loaded into the compare register. Bewdiful! (works on both 8-bit and 32-bit Atsam processors). So that's what I am hoping the ESP32 will do too only better. Output a full pulse train, then update the values from an array somewhere (which has been modified by the program), then output that train, and so ad nauseum. It seems to me this is the way it should work. |
Actually, having studied your code again, I think that's exactly what it is doing. Yippee! |
@mogplus88 if you don’t actually need hardware looping then all you should need to do is If you do need hardware looping then it appears you have to disable the TX interrupt to get correct output. In that case, I’d stick with the ordering in my comment above to avoid blocking. |
Should now be fixed properly by 7dbef53 |
A previous commit 3a9d948 can cause lock-ups of the RMT driver, so this commit reverses that, adds a loop_en flag, and explicitly controls the TX interrupt in write_pulses(). This provides correct looping, non-blocking writes and sensible behaviour for wait_done(). See also micropython#6167.
I know it is over 3 years ago but I'm running stock ESP32_GENERIC-20231005-v1.21.0.bin and getting the same problem as described here. In fact, running the trivial example code stated in the first post here gives the same error, i.e. there is a first erroneous pulse. Should I raise a new bug or should we reopen this one? |
Curious. I've not looked at the RMT code (or used this feature) for an age. Looking at a blame of the source file, I would guess that it is this commit that has changed things: 7ea06a3 I spent a significant amounf of time staring at the code to come up with the ordering I settled on. Unfortunately, I don't have enough time at the moment to figure out what the impact of swapping these operations around is. I suspect that you'll get further opening a new bug saying that there appears to be a regression and link to this one. |
Ditto. Haven't played with this since the original conversation years ago. I'm using the Raspberry Pi Pico for my application now, (generating a PPM stream) using its PIO feature. Happy to share code if you are interested. There are also many websites (related to diy radio control transmitters for model aircraft) that use an Arduino Nano or similar to do the same thing with a few lines of code. I'm a bit over the esp32 I have to say. I'm finding the Pico a much friendlier board. |
Thanks for replying you two. @jonathanhogg FYI, the bug is due to commit 7ea06a3 that you reference. Using latest MP master, if I put that single line back (i.e. above the |
As per original issue mattytrentini#11, in which this bug was more fully discussed, using
loop(True)
with the esp32RMT
object will cause repeated initial pulses.Simple example:
With
loop(False)
this will produce the output show in Figure 1 below, but withloop(True)
it will produce the – erroneous – output shown in Figure 2. The first of the three pulses is repeated.This, it turns out, is a bug in the ESP32 IDF (see espressif/esp-idf#4664) which has a fix committed for it. In the meantime, the accepted workaround is to call
rmt_driver_install
beforermt_config
when initialising the RMT peripheral. This should still be fine after the fix makes a mainline IDF release.The text was updated successfully, but these errors were encountered: