High-precision PWM control with 25MHz clock for servo positioning and motor control
PoKeys devices feature a built-in PWM module operating at 25MHz clock frequency, providing high-precision timing control for servo motors, LED dimming, and motor speed control.
| Pin | Channel | Name | Description |
|---|---|---|---|
| 22 | 0 | PWM1 | Primary PWM output |
| 21 | 1 | PWM2 | Secondary PWM output |
| 20 | 2 | PWM3 | Third PWM output |
| 19 | 3 | PWM4 | Fourth PWM output |
| 18 | 4 | PWM5 | Fifth PWM output |
| 17 | 5 | PWM6 | Sixth PWM output |
All PWM timing values must be expressed as clock cycles at 25MHz frequency:
Clock Cycles = Time (seconds) × 25,000,000
use pokeys_lib::*;
fn main() -> Result<()> {
let mut device = connect_to_device(0)?;
// Configure PWM with 25MHz clock cycles
// 20ms period = 0.020 × 25,000,000 = 500,000 cycles
device.set_pwm_period(500000)?;
// Enable PWM on pin 22 (PWM1)
device.enable_pwm_for_pin(22, true)?;
// Set duty cycle (1.5ms = 37,500 cycles for servo center)
device.set_pwm_duty_cycle_for_pin(22, 37500)?;
println!("PWM active on pin 22");
// Disable PWM
device.enable_pwm_for_pin(22, false)?;
Ok(())
} Complete servo positioning example with calibrated positions:
use pokeys_lib::*;
use std::thread;
use std::time::Duration;
fn main() -> Result<()> {
let mut device = connect_to_device(0)?;
// Configure for servo control (20ms period)
device.set_pwm_period(500000)?;
device.enable_pwm_for_pin(22, true)?;
// Servo positions (calibrated for specific servo)
let positions = [
(60000, "0°"), // Custom calibrated 0° position
(36000, "90°"), // Custom calibrated 90° position
(12000, "180°"), // Custom calibrated 180° position
];
for (duty_cycles, angle) in positions.iter() {
println!(\"Moving to {}\", angle);
device.set_pwm_duty_cycle_for_pin(22, *duty_cycles)?;
thread::sleep(Duration::from_secs(1));
}
// Return to center and disable
device.set_pwm_duty_cycle_for_pin(22, 36000)?;
thread::sleep(Duration::from_millis(500));
device.enable_pwm_for_pin(22, false)?;
Ok(())
} High-level servo control with different servo types:
use pokeys_lib::*;
fn main() -> Result<()> {
let mut device = connect_to_device(0)?;
// 180-degree position servo
let servo_180 = ServoConfig::one_eighty(22, 60000, 12000);
device.configure_servo(servo_180.clone())?;
device.set_servo_angle(&servo_180, 90.0)?; // Move to 90°
// 360-degree position servo (multi-turn)
let servo_360_pos = ServoConfig::three_sixty_position(20, 25000, 50000);
device.configure_servo(servo_360_pos.clone())?;
device.set_servo_angle(&servo_360_pos, 270.0)?; // Move to 270°
// 360-degree speed servo (continuous rotation)
// Datasheet: Counterclockwise 1-1.5ms, Stop 1.5ms, Clockwise 1.5-2ms
let servo_speed = ServoConfig::three_sixty_speed(21, 37500, 50000, 25000);
device.configure_servo(servo_speed.clone())?;
device.set_servo_speed(&servo_speed, 50.0)?; // 50% clockwise
device.stop_servo(&servo_speed)?; // Stop rotation
Ok(())
} For easier control, use percentage-based duty cycle functions:
use pokeys_lib::*;
fn main() -> Result<()> {
let mut device = connect_to_device(0)?;
// Set up PWM
device.set_pwm_period(25000)?; // 1kHz for LED dimming
device.enable_pwm_for_pin(22, true)?;
// Fade LED from 0% to 100%
for brightness in (0..=100).step_by(10) {
device.set_pwm_duty_cycle_percent_for_pin(22, brightness as f32)?;
println!(\"Brightness: {}%\", brightness);
std::thread::sleep(std::time::Duration::from_millis(200));
}
// Turn off
device.enable_pwm_for_pin(22, false)?;
Ok(())
} Control multiple PWM channels simultaneously:
use pokeys_lib::*;
fn main() -> Result<()> {
let mut device = connect_to_device(0)?;
// Configure PWM period (shared by all channels)
device.set_pwm_period(500000)?; // 20ms for servo control
// Enable multiple PWM channels
let servo_pins = [22, 21, 20]; // PWM1, PWM2, PWM3
for pin in servo_pins.iter() {
device.enable_pwm_for_pin(*pin, true)?;
}
// Set different positions for each servo
device.set_pwm_duty_cycle_for_pin(22, 60000)?; // Servo 1 to 0°
device.set_pwm_duty_cycle_for_pin(21, 36000)?; // Servo 2 to 90°
device.set_pwm_duty_cycle_for_pin(20, 12000)?; // Servo 3 to 180°
println!("All servos positioned");
// Disable all channels
for pin in servo_pins.iter() {
device.enable_pwm_for_pin(*pin, false)?;
}
Ok(())
} Check that PWM is enabled and period is set to 500,000 cycles (20ms). Verify duty cycle values are appropriate for your servo (typically 25,000-50,000 cycles).
Servo timing varies by manufacturer. Use the calibration tool to find correct duty cycle values for 0°, 90°, and 180° positions. Speed servos require datasheet timing specifications.
Verify timing matches datasheet: counterclockwise (1-1.5ms), stop (1.5ms), clockwise (1.5-2ms). Use ServoConfig::three_sixty_speed with correct timing values.
Ensure you're using pins 17-22 only. Other pins don't support PWM. Check that the pin isn't configured for another function.