1use core::convert::Infallible;
10
11use arbitrary_int::{prelude::*, u3, u4};
12use zynq7000::ttc::{MmioTtc, TTC_0_BASE_ADDR, TTC_1_BASE_ADDR};
13
14#[cfg(not(feature = "7z010-7z007s-clg225"))]
15use crate::gpio::mio::{Mio16, Mio17, Mio18, Mio19, Mio40, Mio41, Mio42, Mio43};
16use crate::{
17 clocks::ArmClocks,
18 gpio::{
19 IoPeriphPin,
20 mio::{Mio28, Mio29, Mio30, Mio31, MioPin, MuxConfig, Pin},
21 },
22 time::Hertz,
23};
24
25#[derive(Debug, Copy, Clone)]
27pub enum TtcId {
28 Ttc0 = 0,
29 Ttc1 = 1,
30}
31
32#[derive(Debug, Copy, Clone)]
33pub enum ChannelId {
34 Ch0 = 0,
35 Ch1 = 1,
36 Ch2 = 2,
37}
38
39pub trait PsTtc {
40 fn reg_block(&self) -> MmioTtc<'static>;
41 fn id(&self) -> Option<TtcId>;
42}
43
44impl PsTtc for MmioTtc<'static> {
45 #[inline]
46 fn reg_block(&self) -> MmioTtc<'static> {
47 unsafe { self.clone() }
48 }
49
50 #[inline]
51 fn id(&self) -> Option<TtcId> {
52 let base_addr = unsafe { self.ptr() } as usize;
53 if base_addr == TTC_0_BASE_ADDR {
54 return Some(TtcId::Ttc0);
55 } else if base_addr == TTC_1_BASE_ADDR {
56 return Some(TtcId::Ttc1);
57 }
58 None
59 }
60}
61
62pub const TTC_MUX_CONF: MuxConfig = MuxConfig::new_with_l3(u3::new(0b110));
63
64pub trait ClockInPin: MioPin {
65 const ID: TtcId;
66}
67
68pub trait WaveOutPin: MioPin {
69 const ID: TtcId;
70}
71
72impl ClockInPin for Pin<Mio19> {
75 const ID: TtcId = TtcId::Ttc0;
76}
77#[cfg(not(feature = "7z010-7z007s-clg225"))]
78impl ClockInPin for Pin<Mio31> {
79 const ID: TtcId = TtcId::Ttc0;
80}
81#[cfg(not(feature = "7z010-7z007s-clg225"))]
82impl ClockInPin for Pin<Mio43> {
83 const ID: TtcId = TtcId::Ttc0;
84}
85
86impl WaveOutPin for Pin<Mio18> {
87 const ID: TtcId = TtcId::Ttc0;
88}
89#[cfg(not(feature = "7z010-7z007s-clg225"))]
90impl WaveOutPin for Pin<Mio30> {
91 const ID: TtcId = TtcId::Ttc0;
92}
93#[cfg(not(feature = "7z010-7z007s-clg225"))]
94impl WaveOutPin for Pin<Mio42> {
95 const ID: TtcId = TtcId::Ttc0;
96}
97
98impl ClockInPin for Pin<Mio17> {
101 const ID: TtcId = TtcId::Ttc1;
102}
103#[cfg(not(feature = "7z010-7z007s-clg225"))]
104impl ClockInPin for Pin<Mio29> {
105 const ID: TtcId = TtcId::Ttc1;
106}
107#[cfg(not(feature = "7z010-7z007s-clg225"))]
108impl ClockInPin for Pin<Mio41> {
109 const ID: TtcId = TtcId::Ttc1;
110}
111
112impl WaveOutPin for Pin<Mio16> {
113 const ID: TtcId = TtcId::Ttc1;
114}
115#[cfg(not(feature = "7z010-7z007s-clg225"))]
116impl WaveOutPin for Pin<Mio28> {
117 const ID: TtcId = TtcId::Ttc1;
118}
119#[cfg(not(feature = "7z010-7z007s-clg225"))]
120impl WaveOutPin for Pin<Mio40> {
121 const ID: TtcId = TtcId::Ttc1;
122}
123
124pub struct Ttc {
125 pub ch0: TtcChannel,
126 pub ch1: TtcChannel,
127 pub ch2: TtcChannel,
128}
129
130impl Ttc {
131 pub fn new(ps_ttc: impl PsTtc) -> Option<Self> {
136 ps_ttc.id()?;
137 let regs = ps_ttc.reg_block();
138 let ch0 = TtcChannel {
139 regs: unsafe { regs.clone() },
140 id: ChannelId::Ch0,
141 };
142 let ch1 = TtcChannel {
143 regs: unsafe { regs.clone() },
144 id: ChannelId::Ch1,
145 };
146 let ch2 = TtcChannel {
147 regs,
148 id: ChannelId::Ch2,
149 };
150 Some(Self { ch0, ch1, ch2 })
151 }
152}
153
154pub struct TtcChannel {
155 regs: MmioTtc<'static>,
156 id: ChannelId,
157}
158
159impl TtcChannel {
160 pub fn regs_mut(&mut self) -> &mut MmioTtc<'static> {
161 &mut self.regs
162 }
163
164 #[inline]
165 pub fn read_counter(&self) -> u16 {
166 self.regs
167 .read_current_counter(self.id as usize)
168 .unwrap()
169 .count()
170 }
171
172 pub fn id(&self) -> ChannelId {
173 self.id
174 }
175}
176
177#[derive(Debug, thiserror::Error)]
178#[error("invalid TTC pin configuration")]
179pub struct InvalidTtcPinConfigError(pub MuxConfig);
180
181#[derive(Debug, thiserror::Error)]
182#[error("frequency is zero")]
183pub struct FrequencyIsZeroError;
184
185#[derive(Debug, thiserror::Error)]
186pub enum TtcConstructionError {
187 #[error("invalid TTC pin configuration")]
188 InvalidTtcPinConfig(#[from] InvalidTtcPinConfigError),
189 #[error("frequency is zero")]
190 FrequencyIsZero(#[from] FrequencyIsZeroError),
191}
192
193pub fn calc_prescaler_reg_and_interval_ticks(mut ref_clk: Hertz, freq: Hertz) -> (Option<u4>, u16) {
194 let mut prescaler: Option<u32> = None;
196 let mut tick_val = ref_clk / freq;
197 while tick_val > u16::MAX as u32 {
198 ref_clk /= 2;
199 match prescaler {
200 Some(val) => {
201 if val == u4::MAX.as_u32() {
202 break;
203 }
204 prescaler = Some(val + 1);
205 }
206 None => prescaler = Some(0),
207 }
208 tick_val = ref_clk / freq;
209 }
210 (prescaler.map(|v| u4::new(v as u8)), tick_val as u16)
211}
212
213pub struct Pwm {
214 channel: TtcChannel,
215 ref_clk: Hertz,
216}
217
218impl Pwm {
219 pub fn new_with_cpu_clk_and_mio_waveout(
222 channel: TtcChannel,
223 arm_clocks: &ArmClocks,
224 freq: Hertz,
225 wave_out: impl WaveOutPin,
226 ) -> Result<Self, TtcConstructionError> {
227 IoPeriphPin::new(wave_out, TTC_MUX_CONF, None);
228 Ok(Self::new_with_cpu_clk(channel, arm_clocks, freq)?)
229 }
230
231 pub fn new_with_cpu_clk(
233 channel: TtcChannel,
234 arm_clocks: &ArmClocks,
235 freq: Hertz,
236 ) -> Result<Self, FrequencyIsZeroError> {
237 Self::new_generic(channel, arm_clocks.cpu_1x_clk(), freq)
238 }
239
240 pub fn new_generic(
242 channel: TtcChannel,
243 ref_clk: Hertz,
244 freq: Hertz,
245 ) -> Result<Self, FrequencyIsZeroError> {
246 if freq.raw() == 0 {
247 return Err(FrequencyIsZeroError);
248 }
249 let (prescaler_reg, tick_val) = calc_prescaler_reg_and_interval_ticks(ref_clk, freq);
250 let id = channel.id() as usize;
251 let mut pwm = Self { channel, ref_clk };
252 pwm.set_up_and_configure_pwm(id, prescaler_reg, tick_val);
253 Ok(pwm)
254 }
255
256 pub fn set_frequency(&mut self, freq: Hertz) -> Result<(), FrequencyIsZeroError> {
260 if freq.raw() == 0 {
261 return Err(FrequencyIsZeroError);
262 }
263 let id = self.channel.id() as usize;
264 let (prescaler_reg, tick_val) = calc_prescaler_reg_and_interval_ticks(self.ref_clk, freq);
265 self.set_up_and_configure_pwm(id, prescaler_reg, tick_val);
266 Ok(())
267 }
268
269 #[inline]
270 pub fn ttc_channel_mut(&mut self) -> &mut TtcChannel {
271 &mut self.channel
272 }
273
274 #[inline]
275 pub fn max_duty_cycle(&self) -> u16 {
276 self.channel
277 .regs
278 .read_interval_value(self.channel.id() as usize)
279 .unwrap()
280 .value()
281 }
282
283 #[inline]
284 pub fn set_duty_cycle(&mut self, duty: u16) {
285 let id = self.channel.id() as usize;
286 self.channel
287 .regs
288 .modify_cnt_ctrl(id, |mut val| {
289 val.set_disable(true);
290 val
291 })
292 .unwrap();
293 self.channel
294 .regs
295 .write_match_value_0(
296 self.channel.id() as usize,
297 zynq7000::ttc::RwValue::new_with_raw_value(duty as u32),
298 )
299 .unwrap();
300 self.channel
301 .regs
302 .modify_cnt_ctrl(id, |mut val| {
303 val.set_disable(false);
304 val.set_reset(true);
305 val
306 })
307 .unwrap();
308 }
309
310 fn set_up_and_configure_pwm(&mut self, id: usize, prescaler_reg: Option<u4>, tick_val: u16) {
311 self.channel
313 .regs
314 .write_cnt_ctrl(id, zynq7000::ttc::CounterControl::new_with_raw_value(1))
315 .unwrap();
316
317 self.channel
319 .regs
320 .write_clk_cntr(
321 id,
322 zynq7000::ttc::ClockControl::builder()
323 .with_ext_clk_edge(false)
324 .with_clk_src(zynq7000::ttc::ClockSource::Pclk)
325 .with_prescaler(prescaler_reg.unwrap_or(u4::new(0)))
326 .with_prescale_enable(prescaler_reg.is_some())
327 .build(),
328 )
329 .unwrap();
330 self.channel
331 .regs
332 .write_interval_value(
333 id,
334 zynq7000::ttc::RwValue::new_with_raw_value(tick_val as u32),
335 )
336 .unwrap();
337 self.channel
339 .regs
340 .write_match_value_0(id, zynq7000::ttc::RwValue::new_with_raw_value(0))
341 .unwrap();
342 self.channel
343 .regs
344 .write_cnt_ctrl(
345 id,
346 zynq7000::ttc::CounterControl::builder()
347 .with_wave_polarity(zynq7000::ttc::WavePolarity::LowToHighOnMatch1)
348 .with_wave_enable_n(zynq7000::ttc::WaveEnable::Enable)
349 .with_reset(true)
350 .with_match_enable(true)
351 .with_decrementing(false)
352 .with_mode(zynq7000::ttc::Mode::Interval)
353 .with_disable(false)
354 .build(),
355 )
356 .unwrap();
357 }
358}
359
360impl embedded_hal::pwm::ErrorType for Pwm {
361 type Error = Infallible;
362}
363
364impl embedded_hal::pwm::SetDutyCycle for Pwm {
365 #[inline]
366 fn max_duty_cycle(&self) -> u16 {
367 self.max_duty_cycle()
368 }
369
370 #[inline]
371 fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> {
372 self.set_duty_cycle(duty);
373 Ok(())
374 }
375}