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}