This might not be a common issue, that hobbyists run into when creating their projects, because usually the software PWM, offered by the raspberry pi’s RPi.GPIO-Module, is exact enough for dimming some lights or controlling dc-motors. But for real-time and time-critical applications, this is actually an issue:
The pulses created by the RPi.GPIO Python-Library are not very exact (usually something like +/-100µs):
This happens because of the way software runs on a computer. Without digging too deep into the topic of scheduling and multi-tasking let’s just say: the linux OS on the pi has to give itself and other applications, running on the pi, some time too for processing. So your e.g. Python script, which is doing the PWM work, will just get some time for doing it’s stuff before an other app gets it’s runtime. After an undefined period of time (might even take some ms to seconds) the OS will give your PWM-Program the focus again and it can generate some waveform output. And this is the problem: The time is undefined. It might take 1µs and the pulse gets accurate or it might take 127µs and the pulse is malformed. As mentioned above: This is absolutely no issue when dealing with e.g. LEDs. You won’t notice a difference, because the PWM-Signal is used to generate an average voltage.
But what if you need the signal to be very precise? Let’s say with an inaccuracy of max.
+/- 1µs for e.g. transmitting data? You’ll have to use a hardware generated Signal. Luckily the pi can even do this! And with the help of well written high-level libraries you can easily create accurate PWM-Signals with software without having to know anything about the ARM-CPU or about PWM-Registers or about low-level programming. If you want to learn more about the CPU and it’s peripherals anyways, you can read the official documentation: BCM2835-ARM-Peripherals.
After digging a bit into the documentation and after a google search, reading lots of forum posts, i found an easy to use gpio library for the pi. I’ve heard about it before, but I somehow totally forgot about it over the last years. I’m talking about the pigpio library. At this point I want to mention that there are many other good libraries out there, but I liked this the most. Another good one is WiringPi from drogon. He seems to be very active in the Raspberry Pi forums, and the command line tools, that come with WiringPi, are great (you can create pwm-signals from the command-line), but I’ve found the WiringPi-Library to be poorly documented (Not everything, but examples are missing everywhere in the api and also max/min values, etc.). Therefore I’m using pigpio instead.
What I want to create, is this signal:
As you can see, it is a 22.26kHz rectangular wave with a duty cycle of roughly 59% (If you are not familiar with the term duty cycle or PWM in general, watch this video). After taking a quick look into the pigio API i found this method:
With this method you can create a signal just like the one in Image 2. I’ve quickly written the following lines of code in python:
import pigpio import time GPIO = pigpio.pi() # # pigpio uses BROADCOM PIN NUMBERING !!! # HSYNC = 18 # Physical Pin #12 # Set the GPIO-Mode to ALT5 for HW-PWM GPIO.set_mode(HSYNC, pigpio.ALT5) # Start the signal generation # 22,26kHz, 59% Duty Cycle GPIO.hardware_PWM(HSYNC, 22260, 590000) try: # Keep the script running until Ctrl + C are pressed while True: time.sleep(1) except KeyboardInterrupt: pass # Pull down the GPIO-Pin and cleanup with stop() GPIO.write(HSYNC, 0) GPIO.stop()
This script simply uses the pigpio library to create the desired waveform. The infinite while loop is not necessary, but I like to keep the program open and to pull the gpio to zero when ending the script with Ctrl + C. So let’s check, what this script does on the GPIO-Pin:
It looks like I didn’t measure a different signal to the one seen in image 2. The two signals are absolutely the same.
If you need to generate exact pulses (or use a hardware clock signal) with the raspberry pi: It is absolutely possible with low level programming or the use of a good library, but sometimes using the internal clock signals is not precise enough, so be aware of that!