1use crate::clocks::{self};
9use crate::gpio::RPGpio;
10use crate::pio::{Pio, SMNumber, StateMachineConfiguration};
11
12use kernel::utilities::cells::TakeCell;
13use kernel::{hil, ErrorCode};
14
15pub struct PioPwm<'a> {
16    clocks: &'a clocks::Clocks,
17    pio: TakeCell<'a, Pio>,
18}
19
20impl<'a> PioPwm<'a> {
21    pub fn new(pio: &'a mut Pio, clocks: &'a clocks::Clocks) -> Self {
22        Self {
23            clocks,
24            pio: TakeCell::new(pio),
25        }
26    }
27}
28
29impl hil::pwm::Pwm for PioPwm<'_> {
30    type Pin = RPGpio;
31
32    fn start(
33        &self,
34        pin: &Self::Pin,
35        frequency_hz: usize,
36        duty_cycle_percentage: usize,
37    ) -> Result<(), ErrorCode> {
38        let path: [u8; 14] = [
52            0x90, 0x80, 0xa0, 0x27, 0xa0, 0x46, 0x00, 0xa5, 0x18, 0x06, 0xa0, 0x42, 0x00, 0x83,
53        ];
54
55        self.pio.map(|pio| {
56            pio.init();
57            pio.add_program(Some(0), &path).ok();
58            let mut custom_config = StateMachineConfiguration::default();
59
60            let pin_nr = *pin as u32;
61            custom_config.div_frac = 0;
62            custom_config.div_int = 1;
63            custom_config.side_set_base = pin_nr;
64            custom_config.side_set_bit_count = 2;
65            custom_config.side_set_opt_enable = true;
66            custom_config.side_set_pindirs = false;
67            let max_freq = self.get_maximum_frequency_hz();
68            let pwm_period = ((max_freq / frequency_hz) / 3) as u32;
69            let sm_number = SMNumber::SM0;
70            let duty_cycle = duty_cycle_percentage as u32;
71            pio.pwm_program_init(sm_number, pin_nr, pwm_period, &custom_config);
72            pio.sm(sm_number)
73                .push_blocking(pwm_period * duty_cycle / (self.get_maximum_duty_cycle()) as u32)
74                .ok();
75        });
76
77        Ok(())
78    }
79
80    fn stop(&self, _pin: &Self::Pin) -> Result<(), ErrorCode> {
81        self.pio.map(|pio| pio.clear_instr_registers());
82        Ok(())
83    }
84
85    fn get_maximum_duty_cycle(&self) -> usize {
86        10000
88    }
89
90    fn get_maximum_frequency_hz(&self) -> usize {
93        self.clocks.get_frequency(clocks::Clock::System) as usize
94    }
95}