use core::time::Duration;
use pio::InstructionOperands;
use crate::gpio::Level;
use crate::pio::{Common, Config, Direction, Instance, LoadedProgram, Pin, PioPin, StateMachine};
use crate::{Peri, clocks};
fn to_pio_cycles(duration: Duration) -> u32 {
(clocks::clk_sys_freq() / 1_000_000) / 3 * duration.as_micros() as u32 }
pub struct PioPwmProgram<'a, PIO: Instance> {
prg: LoadedProgram<'a, PIO>,
}
impl<'a, PIO: Instance> PioPwmProgram<'a, PIO> {
pub fn new(common: &mut Common<'a, PIO>) -> Self {
let prg = pio::pio_asm!(
".side_set 1 opt"
"pull noblock side 0"
"mov x, osr"
"mov y, isr"
"countloop:"
"jmp x!=y noset"
"jmp skip side 1"
"noset:"
"nop"
"skip:"
"jmp y-- countloop"
);
let prg = common.load_program(&prg.program);
Self { prg }
}
}
pub struct PioPwm<'d, T: Instance, const SM: usize> {
sm: StateMachine<'d, T, SM>,
pin: Pin<'d, T>,
}
impl<'d, T: Instance, const SM: usize> PioPwm<'d, T, SM> {
pub fn new(
pio: &mut Common<'d, T>,
mut sm: StateMachine<'d, T, SM>,
pin: Peri<'d, impl PioPin>,
program: &PioPwmProgram<'d, T>,
) -> Self {
let pin = pio.make_pio_pin(pin);
sm.set_pins(Level::High, &[&pin]);
sm.set_pin_dirs(Direction::Out, &[&pin]);
let mut cfg = Config::default();
cfg.use_program(&program.prg, &[&pin]);
sm.set_config(&cfg);
Self { sm, pin }
}
pub fn start(&mut self) {
self.sm.set_enable(true);
}
pub fn stop(&mut self) {
self.sm.set_enable(false);
}
pub fn set_period(&mut self, duration: Duration) {
let is_enabled = self.sm.is_enabled();
while !self.sm.tx().empty() {} self.sm.set_enable(false);
self.sm.tx().push(to_pio_cycles(duration));
unsafe {
self.sm.exec_instr(
InstructionOperands::PULL {
if_empty: false,
block: false,
}
.encode(),
);
self.sm.exec_instr(
InstructionOperands::OUT {
destination: ::pio::OutDestination::ISR,
bit_count: 32,
}
.encode(),
);
};
if is_enabled {
self.sm.set_enable(true) }
}
pub fn set_level(&mut self, level: u32) {
self.sm.tx().push(level);
}
pub fn write(&mut self, duration: Duration) {
self.set_level(to_pio_cycles(duration));
}
pub fn release(self) -> (StateMachine<'d, T, SM>, Pin<'d, T>) {
(self.sm, self.pin)
}
}