由于gpiozero或者其他树莓派python库的pwm发生都是软件pwm,当进行cpu占用大的处理代码时会导致pwm发生扰动。这里提供一种树莓派5硬件pwm产生的方式。首先,我们需要创建一个设备树覆盖文件来配置GPIO12, GPIO13, GPIO18和GPIO19为PWM模式并启用pwm0。
1.创建一个新的文件,命名为 pwm-pi5-overlay.dts
,内容如下:
/dts-v1/;
/plugin/;
/{
compatible = "brcm,bcm2712";
fragment@0 {
target = <&rp1_gpio>;
__overlay__ {
pwm_pins: pwm_pins {
pins = "gpio12", "gpio13", "gpio18", "gpio19";
function = "pwm0", "pwm0", "pwm0", "pwm0";
};
};
};
fragment@1 {
target = <&rp1_pwm0>;
frag1: __overlay__ {
pinctrl-names = "default";
pinctrl-0 = <&pwm_pins>;
status = "okay";
};
};
};
2. 使用设备树编译器(dtc
)将 .dts
文件编译为 .dtbo
文件:
dtc -I dts -O dtb -o pwm-pi5.dtbo pwm-pi5-overlay.dts
3. 将编译后的 .dtbo
文件复制到 /boot/firmware/overlays/
目录:
sudo cp pwm-pi5.dtbo /boot/firmware/overlays/
4. 在/boot/firmware/config.txt末尾加上:
dtoverlay=pwm-pi5
5.重启树莓派
6.创建一个脚本文件,pwm_control.sh
,并添加以下内容:
#!/bin/bash
NODE=/sys/class/pwm/pwmchip2
PIN="$1"
FUNC="a0"
PERIOD="$2"
DUTY_CYCLE="$3"
function usage {
printf "Usage: $0 <pin> <period> <duty_cycle>\n"
printf " pin - one of 12, 13, 14, 15, 18 or 19\n"
printf " period - PWM period in nanoseconds\n"
printf " duty_cycle - Duty Cycle (on period) in nanoseconds\n"
exit 1
}
if [ -d "$NODE/device/consumer:platform:cooling_fan/" ]; then
echo "Hold your horses, looks like this is pwm1?"
exit 1
fi
case $PIN in
"12")
CHANNEL="0"
;;
"13")
CHANNEL="1"
;;
"14")
CHANNEL="2"
;;
"15")
CHANNEL="3"
;;
"18")
CHANNEL="2"
FUNC="a3"
;;
"19")
CHANNEL="3"
FUNC="a3"
;;
*)
echo "Unknown pin $PIN."
exit 1
esac
function pwmset {
echo "$2" | sudo tee -a "$NODE/$1" > /dev/null
}
if [[ "$PERIOD" == "off" ]]; then
if [ -d "$NODE/pwm$CHANNEL" ]; then
pinctrl set $PIN no
pwmset "pwm$CHANNEL/enable" "0"
pwmset "unexport" "$CHANNEL"
fi
exit 0
fi
if [[ ! $PERIOD =~ ^[0-9]+$ ]]; then
usage
fi
if [[ ! $DUTY_CYCLE =~ ^[0-9]+$ ]]; then
usage
fi
if [ ! -d "$NODE/pwm$CHANNEL" ]; then
pwmset "export" "$CHANNEL"
fi
pwmset "pwm$CHANNEL/enable" "0"
pwmset "pwm$CHANNEL/period" "$PERIOD"
if [ $? -ne 0 ]; then
echo "^ don't worry, handling it!"
pwmset "pwm$CHANNEL/duty_cycle" "$DUTY_CYCLE"
pwmset "pwm$CHANNEL/period" "$PERIOD"
else
pwmset "pwm$CHANNEL/duty_cycle" "$DUTY_CYCLE"
fi
pwmset "pwm$CHANNEL/enable" "1"
pinctrl set $PIN $FUNC
echo "GPIO $PIN (Ch. $CHANNEL, Fn. $FUNC) set to $PERIOD ns, $DUTY_CYCLE."
7.通过以下命令使用PWM控制脚本:
bash pwm_control.sh <pin> <period> <duty_cycle>
8.例如,要在GPIO12上设置周期为20000000ns(20ms),占空比为1500000ns(1.5ms)的PWM信号,可以运行:
bash pwm_control.sh 12 20000000 1500000
9.参考https://gist.github.com/Gadgetoid/b92ad3db06ff8c264eef2abf0e09d569