servo-pio 0.2.1

Control servo motors using the RP2040's PIO peripheral.
Documentation
#![no_std]
#![no_main]

use defmt_rtt as _;
use hal::gpio::{Function, FunctionPio0, Pin, PinId, PullNone, PullType};
use hal::pio::{PIOExt, PinDir};
use hal::Clock;
use panic_probe as _;
use pimoroni_servo2040::hal;
use pimoroni_servo2040::pac;
use pio_proc::pio_file;

#[pimoroni_servo2040::entry]
fn main() -> ! {
    let mut pac = pac::Peripherals::take().unwrap();
    let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);

    let sio = hal::Sio::new(pac.SIO);

    let clocks = hal::clocks::init_clocks_and_plls(
        pimoroni_servo2040::XOSC_CRYSTAL_FREQ,
        pac.XOSC,
        pac.CLOCKS,
        pac.PLL_SYS,
        pac.PLL_USB,
        &mut pac.RESETS,
        &mut watchdog,
    )
    .ok()
    .unwrap();

    let pins = pimoroni_servo2040::Pins::new(
        pac.IO_BANK0,
        pac.PADS_BANK0,
        sio.gpio_bank0,
        &mut pac.RESETS,
    );
    let servo7 = pins.servo7.reconfigure::<FunctionPio0, PullNone>();
    let servo4 = pins.servo4.reconfigure::<FunctionPio0, PullNone>();
    let scl = pins.scl.reconfigure::<FunctionPio0, PullNone>();

    let (mut pio, sm, _, _, _) = pac.PIO0.split(&mut pac.RESETS);
    let pwm_program = pio_file!("./src/pwm.pio", select_program("debug_pwm_cluster"));
    let program = pwm_program.program;
    let installed = pio.install(&program).unwrap();
    const DESIRED_CLOCK_HZ: u32 = 500_000;
    let sys_hz = clocks.system_clock.freq().to_Hz();
    let (int, frac) = (
        sys_hz / DESIRED_CLOCK_HZ,
        (sys_hz as u64 * 256 / DESIRED_CLOCK_HZ as u64) as u8,
    );
    let (mut sm, _, mut tx) = rp2040_hal::pio::PIOBuilder::from_program(installed)
        .out_pins(0, id(&scl))
        .side_set_pin_base(id(&scl))
        .clock_divisor_fixed_point(int as u16, frac)
        .build(sm);
    sm.set_pindirs(
        [(id(&scl), PinDir::Output)].into_iter().chain(
            [id(&servo4), id(&servo7)]
                .into_iter()
                .map(|pin| (pin, PinDir::Output)),
        ),
    );

    let _sm = sm.start();
    let transitions = [
        Transition {
            mask: 1 << id(&servo7),
            delay: 4293,
        },
        Transition {
            mask: 0,
            delay: 26_955,
        },
        Transition {
            mask: 0,
            delay: 31_249,
        },
    ];
    let mut idx = 0;
    let mut is_mask = true;
    loop {
        if !tx.is_full() {
            let value = if is_mask {
                is_mask = !is_mask;
                transitions[idx].mask
            } else {
                let ret = transitions[idx].delay;
                is_mask = true;
                idx = (idx + 1) % transitions.len();
                ret
            };
            tx.write(value);
        } else {
            cortex_m::asm::delay(100);
        }
    }
}

struct Transition {
    mask: u32,
    delay: u32,
}

fn id<I, F, P>(pin: &Pin<I, F, P>) -> u8
where
    I: PinId,
    F: Function,
    P: PullType,
{
    pin.id().num
}