Timing PWM pulse widths on Raspberry Pi 3

nerves

#1

I’m trying to measure pulse widths on Raspberry Pi 3 GPIO pins by listening for rising and falling edges of the pulse. Is there a better way to time these than using System.system_time()? I need sub millisecond accuracy.


#2

Measuring PWM pulse widths like this is unlikely to work very well. You might be able to get some success, but depending on how short the pulses are, and the load on the system, you’re going to get unpredictable timing on your interrupt messages. The best way to do this is with some hardware that would measure the pulses and present them to the Elixir process, for example, using a SPI or I2C interface. One thought would be to try using a microcontroller (like an Arduino) to do the pulse-measuring, and stream the results back to the Pi using the firmata library.

The Raspberry Pi family have PWM hardware for generating PWM waveforms, but I don’t believe you can listen to PWM waveforms. I’m not 100% sure on that, though, so I’d love to be proven wrong.


#3

That’s disappointing. When you say “unpredictable timing on your interrupt messages” are you referring to an Elixir/Nerves limitation or something inherent to the RPi3? Because I found the “PWM Monitor” project on the pigpio project site uses exactly the same approach as me from what I can tell.

With my own code using Nerves/ALE I find that it works great with one PWM signal, but has issues with two. This may be related to the problems you mention. I’m reluctant to roll an Arduino into the project, but would be ok with something simpler. For my application I don’t need the messages to be particularly timely, but the measurement of the pulse widths needs to be precise as they only vary from 1.0 to 2.0 ms. The difference between a 1.5 ms pulse width and a 2.0 ms pulse width is the difference between a motor not moving at all and a motor running at full speed.


#4

I was referring more to Linux itself than anything Nerves-specific, and it’s totally possible that I’m just wrong and your use-case will work fine. I haven’t tried it myself. If pigpio does what you want, you may want to check out the pigpiox library for interacting with it from Elixir/Nerves. If it’s possible for the hardware to do it, I don’t think anything in Elixir/Nerves would prevent it from working.


#5
start = System.monotonic_time()
do_something()
stop = System.monotonic_time()
diff = System.convert_time_unit(stop - start, :native, :micro_seconds)

#6

I’ll check out pigpiox - thanks.


#7

I did not know about System.monotonic_time - thanks!


#8

Hi…Accurate measuring on a multi tasking (not real-time) OS is a challenge.I suggest you have a look at the panaylser: a logic analyser for the PI.They had the same problem and have solved it. As you don’t need an N-channel input I would use their solution as a starting point for making it single channel.