I’m trying to use a PWM Controller connected to below pins in order to control a servo motor.
(I2C7 : SDA on Pin 18, SCL on Pin 17)
My code runs fine, but the servo does not move.
Same code, after changing the pin numbers, works fine on a Raspberry-Pi 4B.
I noted that the pins do not send the correct logic level voltage on the GPIO pins. I see a voltage of 2.7V. I think its supposed to be between 3.3V - 5V if I’m not wrong.
This is my kernel information. We were using Kernel v5 previously and had the same problem. Upgrading the kernel to 6.1.75 has not helped either.
sudo uname -a
Linux vicharak 6.1.75-axon axon SMP Mon Aug 4 10:17:13 IST 2025 aarch64 aarch64 aarch64 GNU/Linux
Has anyone seen this? Any thoughts on how to fix this.
Overlays enabled (from my vicharak-config screenshot):
Enable I2C7 on 30-Pin GPIO Header Axon V0.3 → ENABLED (required for PCA9685 on SDA pin 18 / SCL pin 17).
Enable PWM1_M1 on 30-Pin GPIO Header Axon V0.3 → ENABLED
Enable UART1 on 30-Pin GPIO Header Axon V0.3 → ENABLED (useful for my LiDAR UART connection).
I tried the Raspberry Pi servo test script — it works fine on RPi4B.
On Axon, I used the servo test script but the servo does not move.
vicharak@vicharak:~$ uname -r
6.1.75-axon
@cycloneuav, Mostly it’s because you have not enabled pwm0 device.
I think you just have to add export, set the period, and enable the signal part to your code.
Note
We have found that without an enable signal, Voltage value of PWM GPIO pin is 2.7V.
As we don’t have PCA9685, we have tested directly connecting the Servo Motor wire to the Axon GPIO Header.
Pin 19 => PWM1_M1
Kindly run the script below :
#!/usr/bin/env python3
import os
import time
# PWM sysfs paths
PWM_PATH = "/sys/class/pwm/pwmchip0"
PWM0 = os.path.join(PWM_PATH, "pwm0")
EXPORT = os.path.join(PWM_PATH, "export")
UNEXPORT = os.path.join(PWM_PATH, "unexport")
# Servo PWM parameters (works on your RK3588 driver)
PERIOD = 2000000 # 2 ms period in nanoseconds
DUTY_MIN = 400000 # pulse width for 0°
DUTY_MAX = 1500000 # pulse width for 180°
def angle_to_duty(angle):
"""Convert 0-180° angle to duty cycle in ns"""
return int(DUTY_MIN + (DUTY_MAX - DUTY_MIN) * angle / 180)
def write_pwm(path, value):
with open(path, "w") as f:
f.write(str(value))
def set_angle(angle):
"""Move servo to specified angle"""
duty = angle_to_duty(angle)
write_pwm(os.path.join(PWM0, "duty_cycle"), duty)
print(f"Angle: {angle}°, Duty: {duty}")
def main():
# Export PWM
write_pwm(EXPORT, 0)
time.sleep(1)
# Set period and enable
write_pwm(os.path.join(PWM0, "period"), PERIOD)
write_pwm(os.path.join(PWM0, "enable"), 1)
try:
# Example drastic movements
for angle in [0, 45, 90, 135, 180, 90, 0]:
set_angle(angle)
time.sleep(2) # wait so movement is visible
finally:
# Disable and unexport PWM
write_pwm(os.path.join(PWM0, "enable"), 0)
write_pwm(UNEXPORT, 0)
print("PWM operations completed.")
if __name__ == "__main__":
main()