I would like to set the motor speed of a RPLidar A3 which requires a 25 kHz PWM. So I played around with the following:

from RPi import GPIO
GPIO.setup(12, GPIO.OUT)
pwm = GPIO.PWM(12, 1000)

Unfortunately, it seems the frequency is not 1 kHz, but 873 Hz and the jitter is HUUUUGGGE. With htop I make sure my RPI is very idle.

Last but not least, I cannot get a 25 kHz PWM, the highest seems to be 7.2 kHz.

Is that normal?

enter image description here

  • Pi.GPIO is updated with hardware PWM
    – Milliways
    Oct 12, 2021 at 0:41

4 Answers 4


pigpio supports DMA timed PWM on GPIO 0-31. This has restricted frequencies and resolution.


pigpio also drives hardware PWM on GPIO 12, 13, 18, and 19. This is more flexible and accurate.


There are different function calls for the two types of PWM.

  • Where did you get this info?
    – nowox
    Oct 10, 2021 at 13:53
  • 1
    Added links to the Python API.
    – joan
    Oct 10, 2021 at 15:13
  • Damned! I've found this website before, but I thought it wasn't about RPI because of the URL name and the vintage look :)
    – nowox
    Oct 10, 2021 at 15:16
  • @nowox pigpio is really useful, but my eyes see Pig Pi O not the intended Pi GPIO. Maybe yours did something similar.
    – Chris H
    Oct 11, 2021 at 10:06
  • 1
    @ChrisH Actually you are correct to say the name was for Pi GPIO which conveniently expresses its function. It's just I have always written it as pigpio and internally pronounced it as pig-pee-oh.
    – joan
    Oct 11, 2021 at 11:20

RPi.GPIO only has software PWM - which by its nature is imprecise.

pigpio has hardware timed PWM which is better (and also hardware PWM if you look hard enough).

bcm2835 has hardware PWM and so does WiringPi (but it is deprecated).

My clone of RPi.GPIO (Pi.GPIO) now has hardware PWM in the final stages of testing expected to be released in the next few days.

Pi.GPIO is updated and can be downloaded :-

git clone https://github.com/Milliways2/Pi.GPIO.git

The following code produces the trace below. (The BitScope is a bit slow to capture edges).

#! /usr/bin/env python3
import sys, os, time
import Pi.GPIO as GPIO


# Pi3 & earlier have 19.2MHz clock
# DIVIDER=15  # gives a precise 10kHz signal
# RANGE=128

# Pi4 has 54MHz clock
# DIVIDER=36 # gives a precise 10kHz signal
# RANGE=150
DIVIDER=45 # gives a precise 10kHz signal

def main():




    GPIO.pwm_setRange(PWM1, RANGE)
    GPIO.pwm_Write(PWM1, RANGE//4)   # duty cycle of 25%

    GPIO.pwm_setRange(PWM0, RANGE)
    GPIO.pwm_Write(PWM0, RANGE//2)   # duty cycle of 50%

if __name__ == '__main__':

PWM 50kHz

  • Why is the RPI.GPIO not using the hardware PWM by default? I just noticed the pigpio requires the daemon pigpiod to be started. It looks cumbersome, isn't?
    – nowox
    Oct 10, 2021 at 11:50
  • Also it seems with pi.set_PWM_frequency(12, 25000) I only get 8000. Is this the maximum? I don't find this information in the BCM2711 datasheet.
    – nowox
    Oct 10, 2021 at 11:51
  • 1
    @nowox You would have the developer of RPI.GPIO, as for pigpio - yes you do need the daemon. I thought it would be relatively simple to add hardware PWM, but 2 months later I am forced to revise that opinion; the documentation is obtuse.
    – Milliways
    Oct 10, 2021 at 11:54
  • @nowox I have been running hardware PWM at 10 kHz for a couple of months (in c code) it is just the python which is causing me problems. There is no reason you can't run at a couple of MHz (although you lose resolution). It would only take a few minutes to test @ 100kHz but not tonight, it is already past bedtime.
    – Milliways
    Oct 10, 2021 at 11:59
  • I feel this is a good and reasonable answer, but I take issue with the claim that wiringPi is deprecated. AIUI, the original developer (Gordon) no longer supports wiringPi, but: 1) wiringPi still runs well on current RPi hardware, firmware & software releases, and 2) the wiringPi library remains available through GitHub, and is supported by a team that has assumed Gordon's role.
    – Seamus
    Oct 11, 2021 at 5:43

As Milliways said, you (me) are using the Python GPIO library which uses software emulated PWM, not the hardware PWM.

The easiest solution would be in you case to load the PWM overlay.

dtoverlay pwm pin=12 func=4

Then export a new PWM channel

echo 0 > /sys/class/pwm/pwmchip0/export

You can now set the period and the duty-cycle:

echo 40000 > /sys/class/pwm/pwmchip0/pwm0/period
echo 10000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle 
echo 1 > /sys/class/pwm/pwmchip0/pwm0/enable

What you have is what you want:

enter image description here

  • The sysfs interface is deprecated (although it is unlikely to disappear soon). The PWM is undocumented, and I have always been deterred by "Currently the clock must have been enabled and configured by other means" which is undefined.
    – Milliways
    Oct 11, 2021 at 1:43
  • If you are happy to use the command line interface, you would be better to use PIGS, which is documented and far more flexible. It works well for PWM.
    – Milliways
    Oct 11, 2021 at 1:45

I think the best method is to use a PWM HAT (Adafruit does one - but it seems not to work well with DC Servos) instead of using a RPi. This virtúally guarantees good timing and much less "strain" on the RPi.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.